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

В этом примере мы реализуем и сравним следующие модели:

Модели на основе ошибок:

  • Линейная регрессия
  • Лассо-регрессия

Модель на основе подобия:

  • Ближайшие соседи

Информационная модель:

  • Древо решений
  • Случайный лес
  • Повышение градиента

Как обычно, мы начинаем с загрузки соответствующих библиотек и наборов данных.

import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression, Lasso
from sklearn.neighbors import KNeighborsRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import r2_score, mean_squared_error
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
X_train = pd.read_csv('X_train')
X_test = pd.read_csv('X_test')
y_train = pd.read_csv('y_train')
y_test = pd.read_csv('y_test')

Подбор и оценка модели

Поскольку это проблема регрессии, мы будем использовать R2 и MSE для оценки этих моделей.

R2: рассчитывается как доля дисперсии зависимой переменной, которую можно предсказать по независимым переменным. Интуитивно это можно объяснить тем, что предсказанные данные хорошо соответствуют реальным данным. Хотя R2 обычно находится в диапазоне от 0 до 1, бывают случаи, когда он находится за пределами этого диапазона, что указывает на то, что модель подходит хуже, чем горизонтальная гиперплоскость. Это часто бывает, когда была выбрана неправильная модель (например, использование классификатора в задаче регрессии). Чем выше R2 и ближе к 1, тем лучше.

Среднеквадратическая ошибка (MSE): вычисляется путем получения средних квадратов разностей между прогнозируемым значением и реальным целевым значением. Другая его версия называется RMSE, которая представляет собой квадратный корень из MSE. Чем ниже МСЭ, тем лучше.

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

Давайте подгоним набор для обучения и тестирования к каждой модели и найдем их оценки R2 и MSE:

Давайте определим функции для запуска этих моделей:

Линейная регрессия:

def run_multipleLinearRegressor(X_train, X_test, y_train, y_test):
 slr = LinearRegression()
 slr.fit(X_train, y_train)
 print(‘Train set’)
 pred = slr.predict(X_train)
 print(‘Multiple Linear Regression R2: {}’.format(slr.score(X_train, y_train)))
 print(‘Multiple Linear Regression MSE: {}’.format(mean_squared_error(y_train, pred)))
 
 print(‘Test set’)
 pred = slr.predict(X_test)
 print(‘Multiple Linear Regression R2: {}’.format(slr.score(X_test, y_test)))
 print(‘Multiple Linear Regression MSE: {}’.format(mean_squared_error(y_test, pred)))

Лассо регрессия:

def run_lassoRegressor(X_train, X_test, y_train, y_test):
 lr = Lasso()
 lr.fit(X_train, y_train)
 print(‘Train set’)
 pred = lr.predict(X_train)
 print(‘Simple Linear Regression R2: {}’.format(lr.score(X_train, y_train)))
 print(‘Simple Linear Regression MSE: {}’.format(mean_squared_error(y_train, pred)))
 
 print(‘Test set’)
 pred = lr.predict(X_test)
 print(‘Simple Linear Regression R2: {}’.format(lr.score(X_test, y_test)))
 print(‘Simple Linear Regression MSE: {}’.format(mean_squared_error(y_test, pred)))

Ближайшие соседи:

def run_nearestNeighbors(X_train, X_test, y_train, y_test):
 neigh = KNeighborsRegressor(n_neighbors=50)
 neigh.fit(X_train, y_train)
 print(‘Train set’)
 pred = neigh.predict(X_train)
 print(‘Simple Linear Regression R2: {}’.format(neigh.score(X_train, y_train)))
 print(‘Simple Linear Regression MSE: {}’.format(mean_squared_error(y_train, pred)))
 
 print(‘Test set’)
 pred = neigh.predict(X_test)
 print(‘Simple Linear Regression R2: {}’.format(neigh.score(X_test, y_test)))
 print(‘Simple Linear Regression MSE: {}’.format(mean_squared_error(y_test, pred)))

Древо решений:

def run_decisionTree(X_train, X_test, y_train, y_test):
 dt = DecisionTreeRegressor()
 dt.fit(X_train, y_train)
 print(‘Train set’)
 pred = dt.predict(X_train)
 print(‘Decision Tree R2: {}’.format(dt.score(X_train, y_train)))
 print(‘Decision Tree MSE: {}’.format(mean_squared_error(y_train, pred)))
 
 print(‘Test set’)
 pred = dt.predict(X_test)
 print(‘Decision Tree R2: {}’.format(dt.score(X_test, y_test)))
 print(‘Decision Tree MSE: {}’.format(mean_squared_error(y_test, pred)))

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

def run_randomForests(X_train, X_test, y_train, y_test):
 rf = RandomForestRegressor(n_estimators=200, random_state=39, max_depth=4)
 rf.fit(X_train, y_train)
 print(‘Train set’)
 pred = rf.predict(X_train)
 print(‘Random Forests R2: {}’.format(r2_score(y_train, pred)))
 print(‘Random Forests MSE: {}’.format(mean_squared_error(y_train, pred)))
 
 print(‘Test set’)
 pred = rf.predict(X_test)
 print(‘Random Forests R2: {}’.format(r2_score(y_test, pred)))
 print(‘Random Forests MSE: {}’.format(mean_squared_error(y_test, pred)))

Повышение градиента:

def run_gradientboosting(X_train, X_test, y_train, y_test):
 gb = GradientBoostingRegressor(n_estimators=100,random_state=0)
 gb.fit(X_train, y_train)
 print(‘Train set’)
 pred = gb.predict(X_train)
 print(‘Random Forests R2: {}’.format(r2_score(y_train, pred)))
 print(‘Random Forests MSE: {}’.format(mean_squared_error(y_train, pred)))
 
 print(‘Test set’)
 pred = gb.predict(X_test)
 print(‘Random Forests R2: {}’.format(r2_score(y_test, pred)))
 print(‘Random Forests MSE: {}’.format(mean_squared_error(y_test, pred)))

Затем запустите наш обучающий и тестовый набор для каждого из них, например:

run_randomForests(X_train,
 X_test,
 y_train, y_test)

Напомним, в части 3 у нас есть базовая модель:

Сравните это с нашими лучшими моделями:

Наши новые модели существенно превзошли базовую модель!

Настройка гиперпараметров

Во-первых, что такое гиперпараметр? Гиперпараметр — это параметр для оценщика, который мы можем настроить в соответствии с нашим набором данных. В качестве примера возьмем регрессор случайного леса scikit-learn:

Регрессор случайного леса в пакете scikit-learn имеет несколько гиперпараметров, таких как n_estimators, который обозначает количество деревьев в лесу, по умолчанию установленное на 100 деревьев. Однако возможно ли, что чем больше/меньше деревьев у нас есть, тем лучше наша модель? Настраивая гиперпараметры, мы надеемся найти набор гиперпараметров, который оптимизирует производительность нашей модели.

Мы будем использовать 2 наиболее распространенных метода:

  1. Случайный поиск: мы будем использовать метод RandomizedSearchCV в модуле model_selection scikit-learn. Нам нужно только передать оценщик, гиперпараметры, которые мы хотели бы настроить, а также распределение, количество выборок и метрику оценки. Инструмент случайным образом выберет значения гиперпараметров из заранее заданного распределения и найдет оптимальный гиперпараметр из этих случайно выбранных значений.
  2. Поиск по сетке: после того, как у нас есть список значений гиперпараметров, оптимизированных с помощью случайного поиска, мы можем уточнить это еще на один шаг, проверив близкие значения, поскольку они могут давать еще лучшие результаты, но не были проверены в случайном поиске. Поскольку использование поиска по сетке для широкого набора значений требует много времени, мы сначала выполняем случайный поиск, чтобы приблизиться к возможным значениям, и только затем мы используем поиск по сетке для дальнейшего точного определения оптимального набора значений.

Мы продемонстрируем на модели случайного леса. Начнем с указания диапазона значений, которые гиперпараметры могут принимать при случайном поиске.

# Number of trees in random forest
n_estimators = [int(x) for x in np.linspace(start = 200, stop = 2000, num = 10)]
# Number of features to consider at every split
max_features = [‘auto’, ‘sqrt’]
# Maximum number of levels in tree
max_depth = [int(x) for x in np.linspace(10, 110, num = 11)]
max_depth.append(None)
# Minimum number of samples required to split a node
min_samples_split = [2, 5, 10]
# Minimum number of samples required at each leaf node
min_samples_leaf = [1, 2, 4]
# Method of selecting samples for training each tree
bootstrap = [True, False]
# Create the random grid
random_grid = {‘n_estimators’: n_estimators,
 ‘max_features’: max_features,
 ‘max_depth’: max_depth,
 ‘min_samples_split’: min_samples_split,
 ‘min_samples_leaf’: min_samples_leaf,
 ‘bootstrap’: bootstrap}
print(random_grid)

Примените RandomSearchCV от scikit-learn к обучающему набору:

# Use the random grid to search for best hyperparameters
# First create the base model to tune
rf = RandomForestRegressor()
# Random search of parameters, using 3 fold cross validation, 
# search across 100 different combinations, and use all available cores
rf_random = RandomizedSearchCV(estimator = rf, param_distributions = random_grid, n_iter = 100, cv = 3, verbose=2, random_state=42, n_jobs = -1)
# Fit the random search model
rf_random.fit(X_train, y_train)

Узнайте лучшие параметры:

rf_random.best_params_

Оцените модель:

def evaluate(model, test_features, test_labels):
 pred = model.predict(test_features)
 print(‘Model Performance’)
 print(‘R2: {}’.format(r2_score(test_labels, pred)))
 print(‘MSE: {}’.format(mean_squared_error(test_labels, pred)))
 
 return
base_model = RandomForestRegressor(n_estimators = 10, random_state = 42)
base_model.fit(X_train, y_train)
base_accuracy = evaluate(base_model, X_test, y_test)
best_random = rf_random.best_estimator_
random_accuracy = evaluate(best_random, X_test, y_test)

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

# Create the parameter grid based on the results of random search 
param_grid = {
    'bootstrap': [True],
     'max_depth': [60, 70, 80],
     'max_features': ['auto'],
     'min_samples_leaf': [1,2],
     'min_samples_split': [2, 3],
     'n_estimators': [1300, 1400, 1500]
}

Примените GridSearchCV от scikit-learn к обучающему набору:

# Create a based model
rf = RandomForestRegressor()
# Instantiate the grid search model
grid_search = GridSearchCV(estimator = rf, param_grid = param_grid, 
 cv = 3, n_jobs = -1, verbose = 2)
grid_search.fit(X_train, y_train)

Узнайте лучшие параметры:

grid_search.best_params_

Оцените модель:

base_model = RandomForestRegressor(n_estimators=200, random_state=39, max_depth=4)
base_model.fit(X_train, y_train)
base_accuracy = evaluate(base_model, X_test, y_test)
best_random = rf_random.best_estimator_
random_accuracy = evaluate(best_random, X_test, y_test)
best_grid = grid_search.best_estimator_
grid_accuracy = evaluate(best_grid, X_test, y_test)

Использование гиперпараметров, оптимизированных с помощью поиска по сетке, улучшило производительность при тестировании с оценкой R2 0,793. Сравнивая производительность нашей последней модели с нашей исходной базовой моделью, мы видим значительный скачок благодаря разработке, выбору и настройке функций!

На этом мы завершаем наш пример сквозного машинного обучения. Спасибо за чтение!

Полный блокнот можно найти на Github.

Ссылки на каждую статью:

Часть 0: Постановка задачи

Часть 1: Веб-парсинг

Часть 2: Исследовательский анализ данных

Часть 3: Очистка данных

Часть 4: Разработка функций

Часть 5: Выбор характеристик

Часть 6: Подгонка модели и настройка

Ссылка:

  1. Семинар по науке о данных Энтони Со; доктор Самуэль Асаре; Роберт Тас Джон; Томас В. Джозеф; Эндрю Уорсли
  2. Гиперпараметрическая настройка случайного леса в Python, Уилл Кёрсен