Построить модель прогнозирования веса рыбы

Регрессионный анализ для начинающих — часть 2

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

· Введение
· Часть 2.1. Создание конвейера машинного обучения
Шаг 1. Сбор данных
Шаг 2. Визуализация данных (задайте себе эти вопросы и ответьте на них)
Шаг 3. Очистка данных
Шаг 4. Обучение модели
Шаг 5. Оценка
Шаг 6. Настройка гиперпараметров с использованием hyperopt
Шаг 7. Выберите лучшую модель и прогноз
· Часть 2.2. Анализ алгоритмов машинного обучения
Что такое дерево решений?
Что такое Random Forest?
Что такое Extreme Gradient Boosting? (XGBoost)
Дерево решений против случайного леса против XGBoost
Линейные модели против моделей на основе дерева.
· Заключение

Введение

Как я объяснил в своем предыдущем посте, настоящий специалист по данным думает с точки зрения проблемы/приложения и находит подход к ее решению с помощью языков программирования или фреймворков. В Части 1 задача оценки веса рыбы решалась с использованием линейных моделей машинного обучения, однако сегодня я представлю алгоритмы на основе деревьев, такие как Дерево решений, Случайный лес, XGBoost для решения та же проблема. В первой половине статьи Часть 2.1 я построю модель, а во второй половине Части 2.2 я теоретически объясню каждый алгоритм, сравню их друг с другом и найду их преимущества и недостатки.

видео на YouTube дерева решений!

Часть 2.1 Создание конвейера машинного обучения

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

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

Шаг 1. Соберите данные

Данные представляют собой общедоступный набор данных, который можно скачать с Kaggle.

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from itertools import combinations
import numpy as np
data = pd.read_csv("Fish.csv")

Шаг 2. Визуализируйте данные (задайте себе эти вопросы и ответьте)

  • Как выглядят данные?
data.head()

  • Есть ли в данных пропущенные значения?
data.isna().sum()

  • Каково распределение числовых признаков?
data_num = data.drop(columns=["Species"])

fig, axes = plt.subplots(len(data_num.columns)//3, 3, figsize=(15, 6))
i = 0
for triaxis in axes:
    for axis in triaxis:
        data_num.hist(column = data_num.columns[i], ax=axis)
        i = i+1

  • Каково распределение целевой переменной (веса) по видам рыб?
sns.displot(
  data=data,
  x="Weight",
  hue="Species",
  kind="hist",
  height=6,
  aspect=1.4,
  bins=15
)
plt.show()

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

Шаг 3. Очистите данные

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import  LabelEncoder
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
import xgboost as xgb
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
data_cleaned =   data.drop("Weight", axis=1)
y = data['Weight']
x_train, x_test, y_train, y_test = train_test_split(data_cleaned,y, test_size=0.2, random_state=42)
print(x_train.shape, x_test.shape, y_train.shape, y_test.shape)
# label encoder
label_encoder = LabelEncoder()
x_train['Species'] = label_encoder.fit_transform(x_train['Species'].values)
x_test['Species'] = label_encoder.transform(x_test['Species'].values)

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

Шаг 4. Обучение модели

def evauation_model(pred, y_val):
  score_MSE = round(mean_squared_error(pred, y_val),2)
  score_MAE = round(mean_absolute_error(pred, y_val),2)
  score_r2score = round(r2_score(pred, y_val),2)
  return score_MSE, score_MAE, score_r2score
def models_score(model_name, train_data, y_train, val_data,y_val):
    model_list = ["Decision_Tree","Random_Forest","XGboost_Regressor"]
    #model_1
    if model_name=="Decision_Tree":
        reg = DecisionTreeRegressor(random_state=42)
    #model_2
    elif model_name=="Random_Forest":
      reg = RandomForestRegressor(random_state=42)
        
    #model_3
    elif model_name=="XGboost_Regressor":
        reg = xgb.XGBRegressor(objective="reg:squarederror",random_state=42,)
    else:
        print("please enter correct regressor name")
        
    if model_name in model_list:
        reg.fit(train_data,y_train)
        pred = reg.predict(val_data)
     
        score_MSE, score_MAE, score_r2score = evauation_model(pred,y_val)
        return round(score_MSE,2), round(score_MAE,2), round(score_r2score,2)
model_list = ["Decision_Tree","Random_Forest","XGboost_Regressor"]
result_scores = []
for model in model_list:
    score = models_score(model, x_train, y_train, x_test, y_test)
    result_scores.append((model, score[0], score[1],score[2]))
    print(model,score)

Я тренировал деревья решений, случайный лес XGboost и сохранял все оценки.

Шаг 5. Оцените

df_result_scores = pd.DataFrame(result_scores,columns ["model","mse","mae","r2score"])
df_result_scores

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

Шаг 6. Настройка гиперпараметров с помощью hyperopt

Сегодня мы используем hyperopt для настройки гиперпараметров с помощью алгоритма TPE. »Вместо того, чтобы брать случайные значения из пространства поиска, алгоритм TPE учитывает, что некоторые назначения гиперпараметров (x), как известно, не имеют отношения к конкретным значениям других элементов. В этом случае поиск эффективнее случайного поиска и быстрее жадного поиска.

from hyperopt import hp
from hyperopt import fmin, tpe, STATUS_OK, STATUS_FAIL, Trials
from sklearn.model_selection import cross_val_score
num_estimator = [100,150,200,250]

space=  {'max_depth': hp.quniform("max_depth", 3, 18, 1),
        'gamma': hp.uniform ('gamma', 1,9),
        'reg_alpha' : hp.quniform('reg_alpha', 30,180,1),
        'reg_lambda' : hp.uniform('reg_lambda', 0,1),
        'colsample_bytree' : hp.uniform('colsample_bytree', 0.5,1),
        'min_child_weight' : hp.quniform('min_child_weight', 0, 10, 1),
        'n_estimators': hp.choice("n_estimators", num_estimator),
    }

def hyperparameter_tuning(space):
    model=xgb.XGBRegressor(n_estimators = space['n_estimators'], max_depth = int(space['max_depth']), gamma = space['gamma'],
                         reg_alpha = int(space['reg_alpha']) , min_child_weight=space['min_child_weight'],
                         colsample_bytree=space['colsample_bytree'], objective="reg:squarederror")
    
    score_cv = cross_val_score(model, x_train, y_train, cv=5, scoring="neg_mean_absolute_error").mean()
    return {'loss':-score_cv, 'status': STATUS_OK, 'model': model}


trials = Trials()
best = fmin(fn=hyperparameter_tuning,
            space=space,
            algo=tpe.suggest,
            max_evals=200,
            trials=trials)

print(best)

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

best['max_depth'] = int(best['max_depth']) # convert to int
best["n_estimators"] = num_estimator[best["n_estimators"]] #assing value based on index
reg = xgb.XGBRegressor(**best)
reg.fit(x_train,y_train)
pred = reg.predict(x_test)
score_MSE, score_MAE, score_r2score = evauation_model(pred,y_test) 
to_append = ["XGboost_hyper_tuned",score_MSE, score_MAE, score_r2score]
df_result_scores.loc[len(df_result_scores)] = to_append
df_result_scores

Результат фантастический! Гипернастроенная модель действительно хороша по сравнению с другими алгоритмами. Например, XGboost улучшил результат MAE с 41,65 до 36,33. Это отличная иллюстрация того, насколько мощной является настройка гиперпараметров.

Шаг 7. Выберите лучшую модель и прогноз

# winner
reg = xgb.XGBRegressor(**best)
reg.fit(x_train,y_train)
pred = reg.predict(x_test)
plt.figure(figsize=(18,7))
plt.subplot(1, 2, 1) # row 1, col 2 index 1
plt.scatter(range(0,len(x_test)), pred,color="green",label="predicted")
plt.scatter(range(0,len(x_test)), y_test,color="red",label="True value")
plt.legend()

plt.subplot(1, 2, 2) # index 2
plt.plot(range(0,len(x_test)), pred,color="green",label="predicted")
plt.plot(range(0,len(x_test)), y_test,color="red",label="True value")
plt.legend()
plt.show()

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

Часть 2.2 Анализ алгоритмов ML

Что такое дерево решений?

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

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

width≤5,154: функция и пороговое значение, при котором алгоритм решил разделить выборки данных.

samples = 127: перед разделением имеется 127 точек данных.

значение = 386,794: среднее значение прогнозируемого признака (вес рыбы).

Squared_error = 122928,22: То же, что и MSE(true, pred) — где pred совпадает с значением (средним весом рыбы в выборках).

Таким образом, алгоритм, основанный на пороге width≤5,154, разделяет данные на две части. Но вопрос в том, как алгоритм нашел этот порог? Существует несколько критериев разделения: для задачи регрессии алгоритм CART пытается найти пороговое значение путем жадного поиска таким образом, чтобы средневзвешенное среднее значение MSE обеих подгрупп было сведено к минимуму.

Например, в нашем случае после первого сплита средневзвешенная СКО обеих подгрупп была минимальной по сравнению с другими сплитами.

J(k,t_k) = 88/127 *20583.394 + 39/127 *75630.727 = 37487.69

Проблема с деревом решений:

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

Что такое случайный лес?

Случайный лес представляет собой ансамбль деревьев решений. Интуиция Random Forest состоит в том, чтобы построить несколько деревьев решений, и в каждом дереве решений вместо поиска лучшей функции для разделения данных она искала лучшую функцию среди подмножества функций, поэтому это улучшает разнообразие деревьев. Однако он менее интерпретируем, чем простое дерево решений. Кроме того, для построения требуется большое количество деревьев, что делает алгоритм медленным для приложений реального времени. Как правило, алгоритмы быстро обучаются, но медленно создают прогнозы. Улучшенной версией дерева решений также является XGBoost.

Что такое экстремальное усиление градиента? (XGBoost)

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

Дерево решений, случайный лес и XGBoost

В результате в нашем эксперименте XGboost превзошел другие по производительности. Также теоретически мы можем заключить, что дерево решений является простейшим древовидным алгоритмом, который имеет ограничение нестабильного характера - изменение данных может вызвать большое изменение древовидной структуры, однако он имеет идеальную интерпретируемость. Random Forest и XGboost более сложны. Одно из отличий состоит в том, что Random Forest объединяет результаты в конце процесса (правила большинства), а XGboost объединяет результаты в процессе. В целом XGboost имеет лучшую производительность, чем случайный лес. Однако XGBoost не может быть хорошим выбором, когда у нас много шума в данных, это приведет к переоснащению, и его будет сложнее настроить, чем случайный лес.

Линейные модели против моделей на основе дерева.

  • Линейные модели фиксируют линейные отношения между независимыми и зависимыми переменными, чего нельзя сказать о большинстве реальных сценариев. Однако модели на основе дерева охватывают более сложные отношения.
  • Линейные модели в большинстве случаев нуждаются в масштабировании функций, а древовидные модели — нет.
  • Производительность древовидных моделей во много раз выше, чем у линейных моделей. Наш эксперимент является хорошей иллюстрацией этого: лучшая гипернастроенная линейная модель достигла 66,20 MAE, а лучшая древовидная модель достигла 36,33, что является большим улучшением.
  • Алгоритмы на основе дерева легче интерпретировать, чем линейные модели.

Заключение

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

Вот полный код в моем GitHub.

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



Ссылки

[1] Стефани Глен Дерево решений против случайного леса против машин повышения градиента: простое объяснение (2018)

[2] Вишал Морде Алгоритм XGBoost: Да здравствует она! (2019)

[3] ГАУРАВ ШАРМА, 5 алгоритмов регрессии, которые вы должны знать — Вводное руководство!

[4] Ааршай Джейн, Полное руководство по настройке параметров в XGBoost с кодами на Python

[5] scikit-learn.org, Дерево решений, Понимание структуры дерева решений¶

[6] Hyperopt: распределенная асинхронная оптимизация гиперпараметров

[7] XGboost, Параметры XGBoost

[8] TINU ROHITH D, HyperParameter Tuning — Hyperopt Bayesian Optimization for (Xgboost and Neural network) (2019)

[9] Администратор рабочих мест, Альтернативный метод оптимизации гиперпараметров, который вам нужно знать — Hyperopt (2020)

[10] Орельен Герон, практическое машинное обучение с помощью Scikit-learn и Tensorflow (2019)