Проект машинного обучения с кодом Python

Таблица содержания:

  1. Набор данных
  2. Преодоление данных
  3. Исследование данных
  4. Наводящий вопрос
  5. Подготовьте данные для модели классификации
  6. Моделирование: базовая классификация, SVC, дерево решений и случайный лес
  7. Важность функции
  8. Вывод

Набор данных:

Этот набор данных изначально предоставляется репозиторием машинного обучения UCI (ссылки: https://archive.ics.uci.edu/ml/datasets/wine+quality). Я импортирую набор данных и называю его df. Он имеет 1599 записей и 12 функций. Ниже показаны 12 функций.

df.info()

Вывод:

Ниже представлены первые пять строк набора данных.

df.head()

Вывод:

Преодоление данных:

Проверьте, сколько всего недостающих значений в этом наборе данных.

df.isnull().sum()

Вывод:

fixed acidity           0 
volatile acidity        0 
citric acid             0 
residual sugar          0 
chlorides               0 
free sulfur dioxide     0 
total sulfur dioxide    0 
density                 0 
pH                      0 
sulphates               0 
alcohol                 0 
quality                 0 
dtype: int64

Нет недостающей ценности! Мы в порядке!

Исследование данных:

Поскольку этот набор данных состоит из 12 характеристик красного вина, между ними могут быть сильные корреляции. Меня особенно интересует корреляция «качества» с другими характеристиками, такими как «алкоголь», «pH» или «кислотность». Давайте построим корреляционную матрицу, чтобы быстро увидеть все корреляции между функциями.

import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize=(30,20))
corr = df.corr()
sns.heatmap(corr,annot=True,cmap=sns.diverging_palette(200, 10, as_cmap=True))
plt.show()

Вывод:

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

plt.bar(df['quality'], df['alcohol'])
plt.title('Relationship between alcohol and quality')
plt.xlabel('quality')
plt.ylabel('alcohol')
plt.legend()
plt.show()

Вывод:

Сразу мы знаем, что вина более низкого качества, как правило, имеют более низкий уровень алкоголя. Однако корреляция не указывает на причинно-следственную связь. Таким образом, я хочу дополнительно исследовать 3 основных свойства, которые могут сделать вино хорошим (высококачественным). Это исследование требует использования классификационных моделей, потому что три основных важных свойства могут классифицировать вина на «хорошие» или «обычные».

Наводящий вопрос: Постройте классификационные модели, которые могут предсказать качество вина и определить 3 основных свойства, которые могут сделать вино хорошим.

Подготовьте данные для модели классификации:

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

Сначала я нормализую набор данных. Нормализация данных преобразует данные так, чтобы их распределение имело равномерный диапазон. Здесь важно выровнять диапазоны данных, потому что в нашем наборе данных, например, лимонная кислота и летучая кислотность имеют все свои значения от 0 до 1. Напротив, общий диоксид серы имеет некоторые значения выше 100 и некоторые значения ниже 10. Это несоответствие в диапазонах может вызвать проблему, поскольку небольшое изменение одной функции может не повлиять на другую. Чтобы решить эту проблему, я нормализую диапазоны набора данных до однородного диапазона от 0 до 1.

from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler(feature_range=(0, 1))
normal_df = scaler.fit_transform(df)
normal_df = pd.DataFrame(normal_df, columns = df.columns)
print(normal_df.head())

Вывод:

Затем, чтобы сделать результаты классификации более точными, я создаю новый столбец с именем «хорошее вино» в исходном наборе данных df. «Хорошее вино» означает «да», когда качество равно или выше 7. «Хорошее вино» означает «нет», если качество ниже 7. Классификационные модели, наконец, выдают «да» или «нет» для прогнозирования качества вина.

df["good wine"] = ["yes" if i >= 7 else "no" for i in df['quality']]

Создайте объекты X и целевую переменную y. X - это все характеристики из нормализованного набора данных, кроме «качества». y - это вновь созданная переменная «хорошего вина» из исходного набора данных df.

X = normal_df.drop(["quality"], axis = 1)
y = df["good wine"]

Наконец, я хочу убедиться, что в y достаточно «хорошего вина».

y.value_counts()

Вывод:

no     1382 
yes     217 
Name: good wine, dtype: int64

Визуализируйте счет

sns.countplot(y)
plt.show()

Вывод:

Результат немного несбалансированный, но достаточно справедливый. У нас более 200 хороших вин. Когда мы разделяем наши данные на обучающий набор и набор для тестирования, не забудьте использовать stratify = y, чтобы убедиться, что набор для обучения и тестирования содержит ту же часть «да» и «нет», что и исходный набор данных.

Моделирование:

Разделите X и y на набор данных для обучения и тестирования. Не забудьте использовать stratify = y, чтобы сохранить исходную пропорцию «да» и «нет».

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=2020, stratify=y)

Базовая классификация:

Давайте сначала создадим базовую модель классификации, которая будет служить ориентиром для будущих сравнений.

Я использую DummyClassifier из sklearn и выбираю стратегию «наиболее частая», что означает, что модель всегда будет предсказывать наиболее частую метку в обучающем наборе. Другими словами, эта модель всегда будет выводить «нет» в качестве своего прогноза. Оценка точности составляет 0,86, что является как раз пропорцией отметки «нет» в данных.

from sklearn.dummy import DummyClassifier
dummy_classifier = DummyClassifier(strategy='most_frequent',random_state=2020)
dummy_classifier.fit(X_train,y_train)
acc_baseline = dummy_classifier.score(X_test,y_test)
print("Baseline Accuracy = ", acc_baseline)

Вывод:

Baseline Accuracy =  0.8645833333333334

Модель первая: классификатор опорных векторов

«SVM - это алгоритм машинного обучения с учителем, который эффективен для задач классификации. Он полагается на технику, называемую ядром, для преобразования данных и на основе преобразования находит оптимальный способ разделения данных по меткам ».

1. Подгонка, прогноз и оценка точности:

Давайте подгоним данные обучения к модели SVM.

from sklearn.svm import SVC
svc = SVC(random_state=2020)
svc.fit(X_train, y_train)

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

from sklearn import metrics
from sklearn.metrics import accuracy_score
y_pred = svc.predict(X_test)
print(metrics.accuracy_score(y_test, y_pred))

Вывод:

SVM Accuracy =  0.8854166666666666

Оценка точности (0,88) модели SVM выше, чем базовая точность (0,86).

2. Переоснащение:

Переобучение происходит, когда модель очень хорошо работает с данными обучения, но плохо работает с данными вне обучения. Чтобы обнаружить переобучение, мы можем сравнить показатель точности на обучающем наборе и показатель точности на внеобучающем наборе, чтобы увидеть, существует ли огромное несоответствие.

Однако в нашем случае, поскольку набор данных Wine относительно невелик (всего 1599 записей), я использую перекрестную проверку, чтобы не тратить большую часть данных на проверку и тестирование.

Перекрестная проверка (CV) оценивает обобщенную производительность с использованием тех же данных, которые используются для обучения модели. Идея перекрестной проверки состоит в том, чтобы разделить набор данных на определенное количество подмножеств, а затем использовать каждый из этих подмножеств в качестве тестовых наборов по очереди, используя остальные данные для обучения модели. (Источник: Stack Exchange)

Используйте функцию cross_val_score, чтобы оценить ожидаемую точность модели на данных вне обучения.

from sklearn.model_selection import cross_val_score
scores = cross_val_score(svc, X, y, cv=5)
print(scores.mean())

Вывод:

Cross Validation Score:  0.8642927115987462

Оценка точности данных обучения

y_pred_train = svc.predict(X_train)
print(metrics.accuracy_score(y_train, y_pred_train))

Вывод:

Training Accuracy:  0.8927613941018767

Поскольку точность обучения (0,89) и оценка перекрестной проверки (0,86) близки, мы можем сделать вывод, что переобучения не происходит.

3. Настройте параметры модели:

Чтобы повысить производительность нашей модели SVM, давайте попробуем настроить следующие параметры модели:

  • C: параметр регуляризации
  • ядро: ‘linear’ ‘poly,’ ‘rbf.’

Во-первых, используйте RandomizedSearchCV, чтобы опробовать широкий диапазон значений [0,001,0.01,0.1,1,10,100,1000] для C. RandomizedSearchCV позволяет нам сузить диапазон для C.

from sklearn.model_selection import RandomizedSearchCV
random_grid = {"C": [0.001,0.01,0.1,1,10,100,1000]}
svc_random = RandomizedSearchCV(svc,random_grid,cv=5,random_state=2020)
svc_random.fit(X_train, y_train)
print(svc_random.best_params_)

Вывод:

{'C': 1}

Теперь мы определили, что C должно иметь значение около 1. Перейдите к использованию GridSearchCV для выполнения исчерпывающего поиска по C в диапазоне около 1, в частности, в диапазоне от 0,8 до 1,4 включительно.

from sklearn.model_selection import GridSearchCV
param_dist = {'C': [0.8,0.9,1,1.1,1.2,1.3,1.4],
              'kernel':['linear', 'rbf','poly']}
svc_cv = GridSearchCV(svc, param_dist, cv=10)
svc_cv.fit(X_train,y_train)
print(svc_cv.best_params_)

Вывод:

{'C': 1.3, 'kernel': 'rbf'}

GridSearchCV помогает нам найти лучшие параметры: C = 1.3, kernel = rbf. Давайте использовать лучшие параметры для обучения новой модели SVM.

svc_new = SVC(C = 1.3, kernel = "rbf", random_state = 2020)
svc_new.fit(X_train, y_train)
y_pred_new = svc_new.predict(X_test)
print(metrics.accuracy_score(y_test, y_pred_new))

Вывод:

New SVM accuracy =  0.89375

При настройке гиперпараметров производительность модели SVM увеличивается с 0,885 до 0,894.

Модель вторая: дерево решений

«Дерево решений - это модель классификации в виде древовидной структуры. Он строится с помощью процесса, известного как двоично-рекурсивный. Дерево Decisoin разбивает данные на разделы, а затем разбивает их на каждую из ветвей ».

1. Подгонка, прогноз и оценка точности:

Давайте подгоним данные обучения к модели дерева решений.

from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier(random_state=2020)
dt.fit(X_train, y_train)

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

from sklearn.metrics import plot_confusion_matrix
y_pred = dt.predict(X_test)
metrics.plot_confusion_matrix(dt, X_test, y_test)
plt.show()
print(metrics.accuracy_score(y_test, y_pred))

Вывод:

Decision Tree Accuracy =  0.88125

Модель дерева решений (0,881) по производительности хуже, чем модель SVM (0,894), но лучше, чем базовая классификация (0,86).

2. Переоснащение:

Чтобы увидеть, не переоснащается ли дерево решений, мы можем сначала отобразить дерево решений.

from sklearn import tree
plt.figure(figsize=(40,20))
fn = X.columns
cn = y.unique()
tree.plot_tree(dt, feature_names=fn, class_names=cn, filled=True)
plt.show()

Вывод:

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

scores = cross_val_score(dt, X, y, cv=5)
print("Cross Validation Score: ",scores.mean())

Вывод:

Cross Validation Score:  0.8054917711598746

Оценка точности данных обучения

y_pred_train = dt.predict(X_train)
print(metrics.accuracy_score(y_train, y_pred_train))

Вывод:

Training Accuracy: 1.0

Оценка перекрестной проверки составляет всего 0,81, что даже ниже, чем базовая точность (0,86), в то время как точность обучения составляет 1,0, что означает, что она идеально предсказывает все данные обучения. Модель дерева решений наверняка переоснащается.

Чтобы решить проблему переобучения, я решил сократить некоторые гиперпараметры, такие как максимальная глубина, максимальные характеристики и критерий, с помощью GridSearchCV.

3. Настройте параметры модели:

Я ограничиваю диапазон максимальной глубины от 1 до 5 (включительно) и максимальных характеристик от 1 до 9 (включительно), чтобы упростить модель и решить проблему переобучения. Затем я использую GridSearchCV, чтобы найти лучшие параметры в указанных диапазонах.

param_dist = {"max_depth": range(1,6),
              "max_features": range(1,10),
              "criterion": ["gini", "entropy"]}
dt_cv = GridSearchCV(dt, param_dist, cv=5)
dt_cv.fit(X_train,y_train)
print(dt_cv.best_params_)

Вывод:

{'criterion': 'gini', 'max_depth': 2, 'max_features': 8}

Установите новую модель дерева решений, используя лучшие параметры, указанные выше. Я сократил максимальную глубину до 2 и максимальные характеристики до 8.

dt_new = DecisionTreeClassifier(criterion = "gini",
                                max_depth = 2,
                                max_features = 8,
                                random_state = 2020)
dt_new.fit(X_train, y_train)
y_pred_new = dt_new.predict(X_test)
print(metrics.accuracy_score(y_test, y_pred_new))
scores = cross_val_score(dt_new, X, y, cv=5)
print("Cross Validation Score: ",scores.mean())

Вывод:

New Decision Tree Accuracy:  0.8854166666666666
New Cross Validation Score:  0.8786794670846394

После отсечения производительность модели дерева решений увеличивается с 0,88 до 0,89. Оценка перекрестной проверки увеличилась с 0,81 до 0,88. Что еще более важно, проблема переобучения решается после удаления двух гиперпараметров (максимальная глубина и максимальные характеристики). Давайте визуализируем новое дерево решений.

plt.figure(figsize=(40,20))
tree.plot_tree(dt_new, feature_names=fn, class_names=cn, filled=True)
plt.show()

Вывод:

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

Метод третий: случайный лес

«Случайный лес - это алгоритм метода ансамбля, который строит несколько деревьев решений во время обучения и выводит класс, который является режимом классов».

1. Подгонка, прогноз и оценка точности:

Давайте подгоним данные обучения к модели случайного леса.

from sklearn.ensemble import RandomForestClassifier
rf_model = RandomForestClassifier(random_state = 2020)
rf_model.fit(X_train,y_train)

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

y_pred_rf = rf_model.predict(X_test)
acc_rf = accuracy_score(y_test,y_pred_rf)
print('Accuracy = ', acc_rf)

Вывод:

Accuracy =  0.9166666666666666

Производительность модели случайного леса (0,92) является лучшей по сравнению с двумя вышеупомянутыми, и она намного лучше, чем базовый уровень.

2. Переоснащение:

Проверьте, не происходит ли переобучение для случайного леса.

Используйте функцию cross_val_score, чтобы оценить ожидаемую точность модели на данных вне обучения.

scores = cross_val_score(rf_model, X, y, cv=5)
print("Cross Validation Score: ",scores.mean())

Вывод:

Cross Validation Score:  0.8680466300940439

Оценка точности данных обучения:

y_pred_train = rf_model.predict(X_train)
print(metrics.accuracy_score(y_train, y_pred_train))

Вывод:

Training Accuracy = 1.0

Несмотря на то, что случайный лес скорректировал привычку дерева решений к переобучению (до некоторой степени), несоответствие между оценкой перекрестной проверки и точностью обучения здесь указывает на то, что наша модель случайного леса все еще немного переобучается. Подобно дереву решений, мы можем сократить некоторые гиперпараметры, такие как max-depth и n_estimators, используя GridSearchCV для устранения переобучения.

3. Настройте параметры модели:

См. Текущие используемые параметры

print(rf_model.get_params())

Вывод:

{'bootstrap': True, 'ccp_alpha': 0.0, 'class_weight': None, 'criterion': 'gini', 'max_depth': None, 'max_features': 'auto', 'max_leaf_nodes': None, 'max_samples': None, 'min_impurity_decrease': 0.0, 'min_impurity_split': None, 'min_samples_leaf': 1, 'min_samples_split': 2, 'min_weight_fraction_leaf': 0.0, 'n_estimators': 100, 'n_jobs': None, 'oob_score': False, 'random_state': 2020, 'verbose': 0, 'warm_start': False}

Попробуйте настроить следующие гиперпараметры:

  • n_estimators: количество деревьев в лесу.
  • max depth: максимальная глубина дерева.

Во-первых, используйте RandomizedSearchCV, чтобы опробовать широкий диапазон значений n_estimators и max depth. Я ограничиваю диапазон max_depth от 1 до 15 (включительно) и n_estimators от 100 до 600 (включительно), чтобы упростить модель и решить проблему переобучения.

random_grid = {'max_depth': [1, 5, 10, 15],
'n_estimators': [100,200,300,400,500,600]}
rf_random = RandomizedSearchCV(rf_model,random_grid, n_iter = 50, cv = 5,random_state = 2020)
rf_random.fit(X_train, y_train)
print(rf_random.best_params_)

Вывод:

{'n_estimators': 300, 'max_depth': 10}

RandomizedSearchCV позволяет нам сузить диапазон, сообщая нам, что n_estimators должно иметь значение около 300, а max_depth должно иметь значение около 10. Продолжайте использовать GridSearchCV для выполнения исчерпывающего поиска по n_estimators в более конкретном диапазоне [280 480] и max_depth. в более конкретном диапазоне [7,15].

param_dist = {"max_depth":[7,8,9,10,11,12,13,14,15],      "n_estimators":[280,300,320,350,380,400,420,450,480]}
rf_cv = GridSearchCV(rf_model, param_dist, cv=5)
rf_cv.fit(X_train,y_train)
print(rf_cv.best_params_)

Вывод:

{'max_depth': 14, 'n_estimators': 450}

Установите новую модель случайного леса, используя лучшие параметры, указанные выше.

rf_new = RandomForestClassifier(n_estimators = 450, max_depth =  14, random_state = 2020)
rf_new.fit(X_train,y_train)
y_pred_rf = rf_new.predict(X_test)
acc_rf = accuracy_score(y_test,y_pred_rf)
print('Accuracy = ', acc_rf)
scores = cross_val_score(rf_new, X, y, cv=5)
print("Cross Validation Score: ",scores.mean())

Вывод:

New Random Forest Accuracy = 0.9166666666666666
New Cross Validation Score =  0.868669670846395  

После настройки гиперпараметров n_estimators и max_depth производительность модели случайного леса практически не изменилась. Однако, увеличив n_estimators и уменьшив max_depth, мы сняли проблему переобучения.

Окончательное модельное решение:

  • Окончательная точность набора данных тестирования модели SVC составляет 0,894.
  • Окончательная точность набора данных тестирования модели дерева решений составляет 0,885.
  • Окончательная точность набора данных тестирования случайной модели леса составляет 0,917.

Поскольку модель случайного леса имеет наивысшую точность, я выбрал модель случайного леса в качестве нашей окончательной модели.

Важность функции:

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

imp_rf = pd.DataFrame(zip(X_train.columns, rf_model.feature_importances_),columns = ["feature", "importance"])
imp_rf.set_index("feature", inplace=True)
imp_rf.sort_values(by = "importance", ascending = False, inplace = True)
imp_rf.head()

Вывод:

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

imp_rf.plot.barh(figsize=(10,10))
plt.show()

Вывод:

График более интуитивно показывает, что алкоголь, летучая кислотность и сульфаты имеют больший вес, чем другие, при прогнозировании качества вина.

Вывод:

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

import numpy as np
print(np.average(df[df["good wine"] == "yes"].alcohol))
print(np.average(df[df["good wine"] == "no"].alcohol))

Вывод:

Good Wine =  11.518049155145931 
Regular Wine =  10.251037144235408

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

Сравните разницу в сульфатах для хорошего вина и обычного вина через среднее

print(np.average(df[df["good wine"] == "yes"].sulphates))
print(np.average(df[df["good wine"] == "no"].sulphates))

Вывод:

Good Wine =  0.7434562211981566 
Regular Wine =  0.6447539797395079

Таким образом, вина хорошего качества в среднем имеют более высокий уровень сульфатов.

Сравните разницу в летучей кислотности хорошего и обычного вина через средний

df_good = df[df["good wine"] == "yes"]
df_bad = df[df["good wine"] == "no"]
print(np.average(df_good["volatile acidity"]))
print(np.average(df_bad["volatile acidity"]))

Вывод:

Good Wine = 0.4055299539170507 
Regular Wine = 0.5470224312590448

Таким образом, вина хорошего качества в среднем имеют более низкий уровень летучей кислотности.

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

Спасибо за чтение! 💗

Автор: Цзинъи Фанг