(английский) Машинное обучение — 1 место

1-е тематическое исследование.

Оглавление

  1. "Введение"
  2. Спецификация набора данных
  3. Цели
  4. Модели
  5. Метрика
  6. "Инструменты"
  7. Методология
  8. Исследовательский анализ данных (EDA)
  9. Предварительная обработка данных
  10. Модели машинного обучения (с оценкой)
  11. "Вывод"

Введение

Первый пример, который я покажу, — это самая первая задача, которая потребовала от меня выполнения трех разных алгоритмов машинного обучения для классификации легендарного и нелегендарного покемонов. Да, я работал с набором данных покемонов. Я выбрал эту тему набора данных, поскольку она казалась простой для понимания и подходящей для моего первоначального проекта по машинному обучению и введения в контролируемую проблему. Итак, без лишних слов, давайте углубимся в содержание этого тематического исследования.

Спецификация набора данных

Название: Pokemon
Получено с: kaggle.com (данные о более чем 800 покемонах из всех 7 поколений) взято с https://serebii.net/
Всего записей: 800
Всего функций (полей): 41

Цели

Набор данных имеет одну целевую особенность, что его значение состоит из 0 и 1. В этом случае мы имеем дело с бинарной классификацией. Значение 0 представляет нелегендарного покемона, а значение 1 представляет легендарного покемона. Цель состоит в том, чтобы классифицировать на основе выбранных признаков, является ли покемон легендарным или нелегендарным.

Модели

Есть три алгоритма машинного обучения, специально для задач классификации, которые я сравнивал: логистическая регрессия, K — ближайший сосед и случайный лес.

Показатели

В задаче классификации обычно используются четыре типа измерения: точность, полнота, точность и F1 — оценка. Количественная оценка измерения основана на матрице путаницы.

Инструменты

В этом проекте участвовали python, Jupiter Notebook и библиотеки Python для анализа данных, такие как pandas, NumPy. , matplotlib, seaborn и sci-kit Learn для машинного обучения.

Методология

Я использовал простую методологию для решения этого проекта. Как правило, методология состоит из шести этапов: сбор данных, исследовательский анализ данных (EDA), предварительная обработка данных, разделение данных обучения и тестирования, разработка моделей машинного обучения и оценка показателей производительности. Поток этапов показан на рисунке ниже.

Исследовательский анализ данных (EDA)

EDA стремится дать базовый обзор всех функций в наборе данных и взаимосвязей между функциями. Один из способов, которым мы могли бы выполнить этот этап, — это анализ графического представления. При необходимости может быть выполнен такой подробный описательный анализ центральной тенденции (мода, среднее значение и медиана), дисперсии (дисперсия, стандартное отклонение, диапазон и перекос) и ассоциации (корреляция и хи-квадрат).

Предварительная обработка данных

Выбор функций

Во-первых, мы определили наличие ценности для всех функций. Это действие выполняется путем визуализации отсутствующих входных данных для всех столбцов.

df.isnull().sum()
sns.heatmap(df.isnull(), cbar=False, yticklabels=False)

Всего есть четыре переменные с отсутствующими значениями: height_m, процент_мужской, тип2 и вес_кг. Не все признаки с пропущенными значениями будут импутированы; один будет удален (type2). Действие отбрасывания, потому что нет дополнительной информации о переменной, поэтому вменение невозможно. Таким образом, мы создали функции для приписывания простых средних значений для остальных переменных.

def impute_height(cols):
     gen = cols[0]
     height = cols[1]
     return df[df["generation"] == gen]["height_m"].describe( ["mean"] if pd.isnull(height) else height
df["height_m"] = df[["generation", "height_m"]].apply(impute_height, axis=1)
df["percentage_male"] = df["percentage_male"].fillna(0)
def impute_weight(cols):
     gen = cols[0]
     weight = cols[1]
     return df[df["generation"] == gen]["weight_kg"].describe()["mean"] if pd.isnull(weight) else weight
df["weight_kg"] = df[["generation", "weight_kg"]].apply(impute_weight, axis=1

Теперь у нас больше нет пропущенных значений. Во-вторых, поскольку модель машинного обучения учитывает только числовые признаки, нам нужно отказаться от признаков объектного типа. В качестве примечания: если функция с типом объекта имеет небольшое количество уникальных и интерпретируемых значений, мы можем закодировать ее в числовое представление и продолжить ее включение. В этом случае мы отказались от функций типа2, имени, японского_имя, классификации и способностей, поскольку они обладали слишком большим количеством уникальных значений, не поддающихся интерпретации и не имеющих существенной корреляции с результатом.

df.drop("type2", axis=1, inplace=True) # too much missing value
df.drop("name", axis=1, inplace=True)
df.drop("japanese_name", axis=1, inplace=True)
df.drop("classfication", axis=1, inplace=True) # drop classification columns because it has many categorical values and doesn't have significant correlation to the outcome (legendary or no)
df.drop("abilities", axis=1, inplace=True) # drop abilities column because it has many categorical values and doesn't have significant correlation to the outcome (legendary or no)
df = df[df["capture_rate"] != "30 (Meteorite)255 (Core)"]
df["capture_rate"] = df["capture_rate"].apply(lambda x: int(x)) # convert rate from string to int

Кодирование функций

В-третьих, если мы визуализируем функцию типа 1, мы можем увидеть рисунок ниже.

df["type1"].unique()
sns.countplot(x="type1", data=df, hue="is_legendary")

Из приведенного выше рисунка мы могли понять, что функция type1 имеет разумное количество уникальных значений, поддающихся интерпретации, и оказывает значительное влияние на результат классификации. Таким образом, эта функция может помочь нашей модели машинного обучения классифицировать легендарных и нелегендарных покемонов. Но, поскольку это функция объектного типа, мы можем закодировать ее до включения в модель машинного обучения.

cat_feat = ['type1']
final_df = pd.get_dummies(df, columns=cat_feat, drop_first=True) # used drop_first to avoid dummy variable trap (multicollinearity)

Масштабирование функций

После того, как выбранные функции представлены в виде числовых значений, следующим шагом является масштабирование функций. Масштабирование признаков является вопросом, потому что иногда и на самом деле этот набор данных содержит числовые признаки, которые сильно различаются по величине, единицам и диапазону. Модель будет учитывать только величину признаков без учета единицы измерения. Таким образом, масштабирование этих функций позволит избежать того, что функции с такой высокой величиной будут весить намного больше, чем функции с такими низкими величинами. В процессе масштабирования числовых признаков мы используем объект StandardScaler из библиотеки Python под названием sci-kit — учитесь.

from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(final_df.drop("is_legendary", axis=1))
scaled_feat = ss.transform(final_df.drop("is_legendary", axis=1))
scaled_feat = pd.DataFrame(scaled_feat, columns=final_df.drop("is_legendary", axis=1).columns)

Наконец, все готово. Теперь мы можем перейти к разработке модели машинного обучения. Но сначала нам нужно разделить данные на обучение и тестирование.

Разделить данные поезда и теста

Я не буду углубляться в объяснение методов разделения поездов и данных. Те конкретные вещи в этой статье, по сути, могут быть написаны как целая статья, например, метрики для задачи классификации, перекрестная проверка (для данных обучения и тестирования), выбор функций, масштабирование и т. д. Итак, чтобы не отставать, Я буду держать это простым. Я использую коэффициент разделения данных 30:70, 70% для поезда и 30% для теста.

from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, confusion_matrix
X = scaled_feat
y = final_df["is_legendary"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

Модели машинного обучения

Теперь я буду использовать обучающий набор данных для обучения наших моделей: логистической регрессии, K ближайшего соседа и случайного леса; которые являются общими для решения задач контролируемого обучения. Все эти модели уже доступны в библиотеке Python под названием sci-kit Learn. Проще говоря, научный набор уже состоит из контролируемых и неконтролируемых моделей, таких как K Means, готовых к использованию.

Логистическая регрессия

from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
lr.fit(X_train, y_train)
pred = lr.predict(X_test)

Затем мы можем оценить его, используя тестовые данные с метрикой эффективности классификации, которая также доступна в библиотеке обучения научного набора, которая представляет собой матрицу путаницы.

tn, fp, fn, tp = confusion_matrix(y_test, pred).ravel()
print(confusion_matrix(y_test, pred))
print(classification_report(y_test, pred))

Как я уже упоминал, классификация количественно определяется компонентами матрицы путаницы, а именно истинно отрицательными (TN), ложноположительными (FP), ложноотрицательными (FN) и истинно положительными (TP). Учитывая, что предсказанная функция имеет значения только 0 (ложь) и 1 (истина). Просто TN — это когда модель успешно предсказала нелегендарного покемона. ТП — это когда модель успешно предсказала легендарного покемона. FP — это когда фактическая метка записи равна 0 (не легендарная), но модель предсказывает 1 (легендарная). Принимая во внимание, что FN — это когда фактическая метка записи равна 1 (легендарная), но модель предсказывает 0 (нелегендарная). Мы можем извлечь TN, FP, FN и TP из матрицы путаницы, используя метод .ravel().

Logistic regression - confusion matrix
+--------------------+---------------+-----------+
| Actual / Predicted | Non-legendary | Legendary |
| Non-legendary      | 221           | 2         |
| Legendary          | 0             | 17        |
+--------------------+---------------+-----------+
Logistic regression - classification report
+---------------+----------+-----------+--------+----------+
|     Types     | Accuracy | Precision | Recall | F1-Score |
+---------------+----------+-----------+--------+----------+
| Non-legendary |     0.99 |      1.00 |   0.99 |     1.00 |
| Legendary     |     0.99 |      0.89 |   1.00 |     0.94 |
+---------------+----------+-----------+--------+----------+

Интерпретация результатов этой оценки будет объяснена вместе с остальными моделями машинного обучения и будет сравнена.

K — ближайший сосед

from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=1)
knn.fit(X_train, y_train)
knn_pred = knn.predict(X_test)

Затем мы можем оценить его, используя тестовые данные с матрицей путаницы.

print(confusion_matrix(y_test, knn_pred))
print(classification_report(y_test, knn_pred))
K - nearest neighbor - confusion matrix
+--------------------+---------------+-----------+
| Actual / Predicted | Non-legendary | Legendary |
+--------------------+---------------+-----------+
| Non-legendary      |           217 |         4 |
| Legendary          |             6 |        13 |
+--------------------+---------------+-----------+
K - nearest neighbor - classification report
+---------------+----------+-----------+--------+----------+
|     Types     | Accuracy | Precision | Recall | F1-Score |
+---------------+----------+-----------+--------+----------+
| Non-legendary |    0.96  |      0.97 |   0.98 |     0.98 |
| Legendary     |    0.96  |      0.76 |   0.68 |     0.72 |
+---------------+----------+-----------+--------+----------+

С помощью алгоритма K ближайших соседей мы могли настроить значение k , которое количество ближайших соседей будет учитывать для прогнозирования результатов новых экземпляров. Из отчета о классификации в настоящее время мы можем сказать, что логистическая регрессия работает лучше, чем K ближайший сосед. Мы могли бы снова провести эксперимент с другими значениями k. На приведенном ниже рисунке показана тенденция частоты ошибок при различных значениях k. Протестированные значения k находятся в диапазоне от k= 1 до k= 20.

error_rate = []
for i in range(1, 21):
    knn = KNeighborsClassifier(n_neighbors=i)
    knn.fit(X_train, y_train)
    knn_pred_i = knn.predict(X_test)
    error_rate.append(np.mean(y_test != knn_pred_i))
# visualize the error rate
sns.lineplot(x=list(range(1, 21)), y=error_rate)

Основываясь на заданной частоте ошибок, мы видим, что наименьшая частота ошибок достигается моделью при k = 3. Таким образом, мы можем провести еще один эксперимент с k = 3.

knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X_train, y_train)
knn_pred = knn.predict(X_test)
print(confusion_matrix(y_test, knn_pred))
print(classification_report(y_test, knn_pred))
K - nearest neighbor - confusion matrix - k = 3
+--------------------+---------------+-----------+
| Actual / Predicted | Non-legendary | Legendary |
+--------------------+---------------+-----------+
| Non-legendary      |           221 |         0 |
| Legendary          |             7 |        12 |
+--------------------+---------------+-----------+
K - nearest neighbor - classification report k = 3
+---------------+----------+-----------+--------+----------+
|     Types     | Accuracy | Precision | Recall | F1-Score |
+---------------+----------+-----------+--------+----------+
| Non-legendary |     0.97 |      0.97 |   1.00 |     0.98 |
| Legendary     |     0.97 |      1.00 |   0.63 |     0.77 |
+---------------+----------+-----------+--------+----------+

До этого момента, даже при k = 3, логистическая регрессия по-прежнему работает лучше, чем k ближайших соседей.

Случайный лес

from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(n_estimators=100)
rf.fit(X_train,  y_train)
rf_pred = rf.predict(X_test)

Затем мы можем оценить его, используя тестовые данные с матрицей путаницы.

print(confusion_matrix(y_test,rf_pred))
print(classification_report(y_test, rf_pred))
Random forest - confusion matrix
+--------------------+---------------+-----------+
| Actual / Predicted | Non-legendary | Legendary |
+--------------------+---------------+-----------+
| Non-legendary      |           213 |         1 |
| Legendary          |             1 |        25 |
+--------------------+---------------+-----------+
Random forest - classification report
+---------------+----------+-----------+--------+----------+
|     Types     | Accuracy | Precision | Recall | F1-Score |
+---------------+----------+-----------+--------+----------+
| Non-legendary |     0.99 |      1.00 |   1.00 |     1.00 |
| Legendary     |     0.99 |      0.96 |   0.96 |     0.96 |
+---------------+----------+-----------+--------+----------+

Основываясь на данном результате отчета о классификации и матрице путаницы с помощью Random Forest, мы даже получили лучший результат с точностью до 99%, что означает, что мы предсказали большинство легендарных покемонов и почти сумели предсказать всех не легендарных. Покемон. С этим результатом мы можем сделать вывод, что на данном этапе эксперимента этот тип набора данных лучше работает с алгоритмом случайного леса.

Заключение

Основываясь на конечном результате, после того, как мы провели сравнение между тремя алгоритмами машинного обучения классификации, а именно логистической регрессией, K ближайшим соседом и случайным лесом, мы обнаружили разные результаты оценки производительности, которая была определена на основе матрицы путаницы и отчета о классификации. . Из обзора приведенных результатов можно сказать, что между ними нет большого разрыва или разницы. Но действительно, есть модель алгоритма, которая работает лучше, чем другой алгоритм с этим набором данных. Мы могли бы ранжировать от лучшего к плохому по каждой метрике отчета о классификации: точность, достоверность, полнота и оценка F1 для каждого алгоритма следующим образом:

1. Точность: 1 случайный лес, 2 логическая регрессия, 3 к ближайших соседей

2. Точность: 1 случайный лес, 2 логическая регрессия, 3 к ближайших соседей

3. Вспомнить: 1 Случайный лес, 2 Логистическая регрессия, 3 К ближайших соседей

4. F1 — Оценка: 1-й случайный лес, 2-й логистический регрессионный, 3-й K ближайших соседей

Судя по рейтингу каждой метрики классификации, мы можем сказать, что алгоритм случайного леса дал лучший результат среди других алгоритмов классификации для этого типа набора данных.