Kostenlos

Машинное обучение доступным языком

Text
Als gelesen kennzeichnen
Schriftart:Kleiner AaGrößer Aa

Валидация

(validation – проверка) метод оценки модели. Выделяют несколько методов7, но мы воспользуемся k-блочной кросс-валидацией (k-fold cross-validation).

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

Преимущество заключается в том, что все наблюдения используются как для обучения, так и для проверки, а каждое наблюдение используется один раз для проверки. Обычно мы разбиваем датасет на 5 или 10 частей: это обеспечивает баланс между вычислительной сложностью и точностью.

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

Получим список предсказаний по тестовым данным и вычислим эффективность кросс-валидации. Метод mean() усреднит показатель 10 разбиений:

tr_pred = tr.predict(X_test)

cv_tr = cross_val_score(tr, X_train, y_train, cv=10).mean()

Мы записали конечный показатель эффективности в переменную cv_tr и скоро узнаем ее значение. Этот показатель называется доля правильных ответов (accuracy). Он измеряет отношение правильно спрогнозированных наблюдений к общему их количеству. “Сколько процентов от общего числа клиентов, взявших или не взявших кредит, модель распознала верно?”

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

• Точность (precision), долю объектов, названных моделью положительными и при этом действительно являющимися положительными “Сколько процентов статусов клиентов модель угадала?”

• Полнота (recall): показывает, какую долю объектов положительного класса из всех объектов положительного класса нашел алгоритм. “Сколько процентов взявших кредит угадала модель?”

• F1-скор (F1 score): объединяет точность и полноту в одно число, и позволяет оценить баланс между этими двумя метриками. Это полезно, когда есть класс большинства, “сбивающий прицел” обеим метрикам выше.

print('Доля правильных ответов: %.3f' % tr.score(X_test, y_test))

print('Доля правильных ответов на кросс-валидации: %0.3f' % cv_tr)

print('Точность: %.3f' % precision_score(y_test, tr_pred))

print('Полнота: %.3f' % recall_score(y_test, tr_pred))

print('F1-мера: %.3f' % f1_score(y_test, tr_pred))

Вот такие мы получаем показатели:

Доля правильных ответов: 0.910

Доля правильных ответов во время кросс-валидации: 0.908

Точность результата измерений: 0.946

Отзыв: 0.953

Оценка F1: 0.950

Доля правильных ответов равна 91%. Звучит неплохо, не так ли? Внедрим для надежности еще одну метрику под названием AUC ROC (area under curve – площадь под кривой, receiver operating characteristic – рабочая характеристика приёмника). Аббревиатура расшифровывается запутанно, так что давайте разберемся постепенно.

Кривая ROC – графическое представление производительности модели:


ROC-кривая полукруглой формы

AUC ROC показывает компромисс между двумя показателями:

• чувствительность (sensitivity) – это доля наблюдений, которые являются истинно положительными (“взял кредит”) и размечены моделью как положительные.

• специфичность (specificity) – это доля наблюдений, которые являются истинно отрицательными (“не взял кредит”) и размечены моделью как отрицательные.

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

Модель с AUC, равной единице, является идеальным классификатором. То есть розовая фигура якобы заполонила собой все пространство в левой верхней половине графика.

Прямая из начала координат под углом 45 градусов – это изображение случайного угадывания. При сбалансированных классах вероятность угадать равна 50%, то есть 0.5 на языке AUC.

Если кривая “уплощается” и как бы совпадает такой прямой, то модель работает как случайное угадывание. Такой результат никого не устроит.

AUC ROC – это способ измерить, насколько хорошо модель может различать два класса. Более высокий показатель означает лучшую производительность модели.

Scikit-learn и тут упрощает нам подсчет площади ROC-кривой:

tr_probs = tr.predict_proba(X_test)

tr_probs = tr_probs[:, 1]

auc_tr = roc_auc_score(y_test, tr_probs)

print('AUC: %.2f' % auc_tr)

Показатель близок к единице, и это замечательно!

AUC: 0.93

Еще один важный инструмент оценки качества – матрица ошибок (confusion matrix). Это показатель успешности классификации, таблица с четырьмя различными комбинациями:

• Истинно позитивное предсказание (true positive, сокр. TP). Модель предсказала положительный результат, и клиент действительно взял кредит. Доля таких предсказаний – уже известная нам чувствительность.

• Истинно негативные предсказание (true negative, TN). Модель предсказала отрицательный результат, и клиент действительно не взял кредит. Доля TN – это специфичность.

• Ошибочно позитивные предсказание (ошибка типа I, false positive, FN). Предсказан положительный результат (клиент возьмет кредит), но на самом деле этого не происходит.

• Ошибочно негативные предсказание (ошибка типа II, false negative, FN). Клиент не должен был взять кредит, но сделал это.



Посмотрим, как наше дерево решений умеет отделять зерна от плевел. Здесь снова нам поможет всемогущий scikit-learn и его класс confusion_matrix. Мы загружаем сгенерированные на тестовом наборе предсказания. sns.heatmap() создаст тепловую карту. Подпишем оси x и y.

tr_matrix = confusion_matrix(y_test, tr_pred)

sns.set(font_scale=1.3)

plt.subplots(figsize=(8,8))

sns.heatmap(tr_matrix, annot=True, cbar=False, cmap='twilight', linewidth=0.5, fmt="d")

plt.ylabel('Истинный класс')

plt.xlabel('Предсказанный класс')

plt.title('Матрица ошибок дерева решений');

Теперь сопоставим термины с результатами:

Истинно позитивное предсказание: 10464

Истинно негативные предсказание: 776

Ошибочно позитивные предсказание: 594

Ошибочно негативные предсказание: 519



Наша тестовая выборка состоит из 30% от исходного числа записей (36K). Среди них преобладает доля взявших кредит. Нам есть куда расти, модель стоит улучшить.

Регуляризация



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

Scikit-learn предлагает нам утилиту для автоматического подбора наилучших параметров дерева. Называется она GridSearchCV и позволяет использовать разные параметры регуляризации. Они аналогичны компонентам двигателя. Меняя значение одного, мы воздействуем на всю модель.



Мы возьмем индекс Gini и энтропию (entropy). Последняя означает меру примеси в наборе данных.



Низкая (слева) и высокая энтропия

Аббревиатура cv означает уже знакомую нам кросс-валидацию, то есть GridSearchCV 10 раз соберет модель, чтобы вычислить ее наилучшие параметры. n_jobs позволяет распараллелить вычисления, но для такого небольшого датасета в этом нужды нет. verbose дает посмотреть на подробные выходные сведения о процессе. max_depth позволяет сделать дерево решений высотой в 20 уровней.

parameters = {'criterion':['gini','entropy']

'max_depth':[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]}


default_tr = tree.DecisionTreeClassifier(random_state=25)

gs_tree = GridSearchCV(default_tr, parameters, cv=10, n_jobs=-1, verbose=1)

gs_tree.fit(X_train, y_train)

Обновим значения метрик:

print('Лучшие параметры дерева решений: {}'.format(gs_tree.best_params_))

print('Доля правильных ответов: %0.3f' % (gs_tree.score(X_test,y_test)))

print('Доля правильных ответов кросс-валидации: %0.3f' % gs_tree.best_score_)

print('Точность: %.3f' % precision_score(y_test, gs_tree_pred))

print('Полнота: %.3f' % recall_score(y_test, gs_tree_pred))

print('F1-мера: %.3f' % f1_score(y_test, gs_tree_pred))

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

Лучшие параметры дерева решений: {'criterion': 'gini', 'max_depth': 5}

Доля правильных ответов: 0.915

Доля правильных ответов кросс-валидации: 0.913

Точность: 0.936

Полнота: 0.970

F1-мера: 0.953

Теперь дадим модели тестовые, неизвестные данные и соберем в gs_tree_probs ее предсказания в виде таблицы. Срез [:, 1] создаст из нее список. Оценим динамику AUC ROC.

 

gs_tree_probs = gs_tree.predict_proba(X_test)

gs_tree_probs = gs_tree_probs[:, 1]

gs_tree_auc = roc_auc_score(y_test, gs_tree_probs)

print('AUC: %.2f' % gs_tree_auc)

Значение площади значительно не изменилось.

AUC: 0.93

Теперь визуализируем нашу ROC-кривую со всеми прилагающимися элементами. Для этого мы создадим переменные gs_tr_fpr (доля ложно позитивных предсказаний), gs_tr_tpr (доля истинно позитивных), gs_tr_thresholds (порог отсечки).

gs_tr_fpr, gs_tr_tpr, gs_tr_thresholds = roc_curve(y_test, gs_tree_probs)

Мы дважды построим ROC-кривые: первую версию дерева решений красным цветом и улучшенную зеленым.

tr_fpr, tr_tpr, tr_thresholds = roc_curve(y_test, tr_probs)

Зададим размер графика в 8 х 8 дюймов. В легенду зашьем и значение площади для ROC-кривой. Построим прямую случайной классификации между двух точек с координатами [0, 1] и [1, 0]. Установим темно-синюю цветовую схему в color. Зададим заголовки осей x и y с помощью xlabel, ylabel. Прикрепим легенду к правому верхнему углу (upper left). size, равный 10, задает размер шрифта.

plt.figure(figsize=(8,8))

plt.plot(tr_fpr, tr_tpr, color='red', label='ROC-кривая дерева решения (AUC= %0.2f)'% auc_tr)


plt.plot(gs_tr_fpr, gs_tr_tpr, color='green', label='ROC-кривая GridSearch + Дерево решений (AUC= %0.2f)'% gs_tr_auc)

7С полным списком можно ознакомиться на сайте (helenkapatsa.ru/vidy-validatsii).