Оценка модели, настройка модели

Добро пожаловать во вторую часть серии статей о прогнозировании стоимости такси с помощью машинного обучения! Это уникальный вызов, не правда ли? Мы регулярно ездим на такси (иногда даже ежедневно!), И тем не менее, когда мы нажимаем кнопку «Забронировать», мы полагаемся на ручные оперативные вычисления, а не на сложные методы машинного обучения. И это то, что я хочу здесь продемонстрировать.

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

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

Дорожная карта

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

  1. Подготовка данных для построения модели
  2. Создание базового прогноза
  3. Создание моделей без проектирования элементов
  4. Построение моделей с помощью проектирования элементов

Подготовка данных

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

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

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

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

Простые модели, такие как линейная регрессия, не запоминают базовые данные, а вместо этого имеют простые предположения о данных. Следовательно, эти модели имеют очень высокую ошибку (высокое смещение), но низкую дисперсию. Набор данных проверки поможет нам оценить модели на основе дисперсии и смещения. В этом анализе мы будем хранить 25% наших данных в качестве данных проверки.

from sklearn.model_selection import train_test_split
X=train.drop([fare_amount],axis=1)
y=train[fare_amount]
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.25,random_state=123)#test_size is the proportion of data that is to be kept aside for validation

Базовая модель

Базовая модель - это решение проблемы без применения каких-либо методов машинного обучения. Любая модель, которую мы строим, должна улучшать это решение. Некоторые способы построения базовой модели включают использование наиболее распространенного значения в случае классификации и вычисление среднего значения в задаче регрессии. В этом анализе, поскольку мы прогнозируем сумму тарифа (которая является количественной переменной), мы прогнозируем среднюю сумму тарифа. В результате RMSE составил 9,71. Таким образом, любая модель, которую мы создаем, должна иметь среднеквадратичное значение ниже 9,71.

avg_fare=round(np.mean(y_train),2) #11.31
baseline_pred=np.repeat(avg_fare,y_test.shape[0])
baseline_rmse=np.sqrt(mean_squared_error(baseline_pred, y_test))
print("Basline RMSE of Validation data :",baseline_rmse)

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

1. Без проектирования функций

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

  • Линейная регрессия
  • Случайный лес
  • Легкая ГБМ

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

  1. Упаковка. В этом методе создается несколько моделей, а прогноз на выходе - это средние прогнозы различных моделей. В Bagging вы берете образцы начальной загрузки (с заменой) вашего набора данных, и каждый образец обучает слабого ученика. Случайный лес использует этот метод для прогнозов. В случайном лесу создается несколько деревьев решений, и на выходе получается средний прогноз каждого из этих деревьев. Чтобы этот метод работал, базовые модели должны иметь меньшее смещение (коэффициент ошибок).
  2. Повышение уровня: в этом методе несколько слабых учеников объединяются, чтобы создать сильных учеников. Boosting использует все данные для обучения каждого учащегося. Но экземплярам, ​​которые были неправильно классифицированы предыдущими учащимися, придается больший вес, чтобы последующие учащиеся могли уделять им больше внимания во время обучения. XGBoost и Light GBM основаны на этом методе. Оба они являются вариациями деревьев принятия решений по повышению градиента (GBDT). В GBDT деревья решений обучаются итеративно, то есть по одному дереву за раз. XGBoost и Light GBM используют стратегию роста по листам при выращивании дерева решений. При обучении каждого дерева решений и разделении данных XGBoost следует поэтапной стратегии, в то время как Light GBM следует поэтапной стратегии.

Наконец-то пришло время создавать наши модели!

  1. Линейная регрессия: используется для нахождения линейной связи между целевым объектом и одним или несколькими предикторами. Основная идея - определить линию, которая лучше всего соответствует данным. Линия наилучшего соответствия - это та, для которой ошибка прогноза наименьшая. Этот алгоритм не очень гибкий и имеет очень большое смещение. Линейная регрессия также очень чувствительна к выбросам, поскольку она пытается минимизировать сумму квадратов ошибок.
lm = LinearRegression()
lm.fit(X_train,y_train)
y_pred=np.round(lm.predict(X_test),2)
lm_rmse=np.sqrt(mean_squared_error(y_pred, y_test))
lm_train_rmse=np.sqrt(mean_squared_error(lm.predict(X_train), y_train))
lm_variance=abs(lm_train_rmse - lm_rmse)
print("Test RMSE for Linear Regression is ",lm_rmse)
print("Train RMSE for Linear Regression is ",lm_train_rmse)
print("Variance for Linear Regression is ",lm_variance)

Тестовая RMSE для модели линейной регрессии составила 8,14, а RMSE обучения - 8,20. Эта модель является улучшением базового прогноза. Тем не менее, частота ошибок в этой модели очень высока, хотя дисперсия очень мала (0,069). Теперь давайте попробуем более сложную модель.

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

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

rf = RandomForestRegressor(n_estimators = 100, random_state = 883,n_jobs=-1)
rf.fit(X_train,y_train)
rf_pred= rf.predict(X_test)
rf_rmse=np.sqrt(mean_squared_error(rf_pred, y_test))
print("RMSE for Random Forest is ",rf_rmse)

Модель случайного леса дала RMSE 3,72 по данным проверки и RMSE обучения 1,41. Существуют огромные различия в RMSE обучения и проверки, указывающие на переобучение. Чтобы уменьшить переоснащение, мы можем настроить эту модель.

3. LightGBM

LightGBM - это алгоритм на основе дерева повышения. Разница между Light GBM и другими древовидными алгоритмами заключается в том, что Light GBM растет по листам, а не по уровням. Этот алгоритм выбирает узел, который приведет к максимальным потерям дельты для разделения. Light GBM очень быстр, требует гораздо меньше оперативной памяти для работы и ориентирован на точность результата.

train_data=lgb.Dataset(X_train,label=y_train)
param = {'num_leaves':31, 'num_trees':5000,'objective':'regression'}
param['metric'] = 'l2_root'
num_round=5000
cv_results = lgb.cv(param, train_data, num_boost_round=num_round, nfold=10,verbose_eval=20, early_stopping_rounds=20,stratified=False)
lgb_bst=lgb.train(param,train_data,len(cv_results['rmse-mean']))
lgb_pred = lgb_bst.predict(X_test)
lgb_rmse=np.sqrt(mean_squared_error(lgb_pred, y_test))
print("RMSE for Light GBM is ",lgb_rmse)

Эта модель дала RMSE 3,78 по данным проверки, но смещение выше, чем у случайного леса. С другой стороны, дисперсия этой модели составила 0,48 по сравнению с 2,31 в нашей модели случайного леса.

Поскольку Light GBM имеет сравнимую частоту ошибок с Random Forest, имеет меньшую дисперсию и работает быстрее, чем последний, мы будем использовать LightGBM в качестве нашей модели для дальнейшего анализа.

2. Разработка функций и настройка модели

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

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

Применение той же модели Light GBM, описанной выше, к данным, разработанным для этой функции, дало RMSE 3,641 (снижение с 3,78) и дисперсию 0,48.

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

  1. max_depth: это максимальная глубина дерева. Поскольку LightGBM следует за ростом по листу, если его не настроить, глубина может быть намного выше по сравнению с другими древовидными алгоритмами.
  2. подвыборка: указывает, какая часть данных должна использоваться на каждой итерации, и используется для ускорения алгоритма и контроля переобучения.
  3. colsample_bytree: это доля функций, которые должны использоваться на каждой итерации процесса построения дерева.
  4. min_child_samples: Это указывает минимальное количество выборок, которое может присутствовать в листовом узле. Это помогает контролировать переоснащение.

Я использовал библиотеку hyperopt в Python для настройки модели. Hyperopt - это пакет поиска по гиперпараметрам, который реализует различные алгоритмы поиска для поиска наилучшего набора гиперпараметров в пространстве поиска. Чтобы использовать Hyperopt, мы должны укажите функцию цели / потерь для минимизации, пространство поиска и базу данных испытаний (необязательно, MongoTrials можно использовать для распараллеливания поиска). Для нашей проблемы цель состоит в том, чтобы минимизировать RMSE и определить лучший набор параметров. Мы настроим параметры max_depth, subsample и colsample_bytree с помощью hyperopt.

Целевая функция, которая будет использоваться для настройки, состоит в том, чтобы минимизировать RMSE в LightGBM Regressor, учитывая набор параметров.

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

def objective(space):
clf = lgb.LGBMRegressor(
          objective = 'regression',
          n_jobs = -1, # Updated from 'nthread'
          verbose=1,
          boosting_type='gbdt',
        num_leaves=60,
        bagging_freq=20,
       subsample_freq=100,
    max_depth=int(space['max_depth']),
    subsample=space['subsample'],
        n_estimators=5000,
    colsample_bytree=space['colsample'])
          #metric='l2_root')
eval_set=[( X_train, y_train), ( X_test,y_test)]
clf.fit(X_train, np.array(y_train),
            eval_set=eval_set,eval_metric='rmse',
            early_stopping_rounds=20)
pred = clf.predict(X_test)
    rmse = np.sqrt(mean_squared_error(y_test, pred))
    print("SCORE:", rmse)
return{'loss':rmse, 'status': STATUS_OK }
space ={
        'max_depth': hp.quniform("x_max_depth", 5, 30, 3),
       
        'subsample': hp.uniform ('x_subsample', 0.8, 1),
        'colsample':hp.uniform ('x_colsample', 0.3, 1)
    }
trials = Trials()
best = fmin(fn=objective,
            space=space,
            algo=tpe.suggest,
            max_evals=100,
            trials=trials)
print(best)

Лучшими параметрами, которые мы получили для LightGBM с помощью разработки функций, были:

{'max_depth': 24.0, 'subsample': 0.9988461076307639, 'colsample_bytree': 0.38429620148564814}

Используя эти параметры, модель LightGBM дала среднеквадратичное значение 3,633 и дисперсию 0,44. Мы можем дополнительно улучшить эту модель, настроив другие параметры, такие как num_leaves, и добавив регуляризацию L1 и L2. параметры.

Конец заметок

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

Надеюсь, вы нашли эту статью полезной. Если у вас есть какие-либо вопросы или отзывы, напишите нам в разделе комментариев ниже.