(английский) Машинное обучение — 1 место
1-е тематическое исследование.
Оглавление
- "Введение"
- Спецификация набора данных
- Цели
- Модели
- Метрика
- "Инструменты"
- Методология
- Исследовательский анализ данных (EDA)
- Предварительная обработка данных
- Модели машинного обучения (с оценкой)
- "Вывод"
Введение
Первый пример, который я покажу, — это самая первая задача, которая потребовала от меня выполнения трех разных алгоритмов машинного обучения для классификации легендарного и нелегендарного покемонов. Да, я работал с набором данных покемонов. Я выбрал эту тему набора данных, поскольку она казалась простой для понимания и подходящей для моего первоначального проекта по машинному обучению и введения в контролируемую проблему. Итак, без лишних слов, давайте углубимся в содержание этого тематического исследования.
Спецификация набора данных
Название: 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 ближайших соседей
Судя по рейтингу каждой метрики классификации, мы можем сказать, что алгоритм случайного леса дал лучший результат среди других алгоритмов классификации для этого типа набора данных.