Важные шаги для оптимизации производительности модели

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

Набор данных и блокнот .ipynb для этой статьи можно найти в моем репозитории Github. В блокноте вы найдете пошаговое руководство по рабочему процессу, которое может быть очень полезным для тех, кто только начинает свой путь в Data Science & ML. Здесь я буду представлять только важные ячейки кода и комментарии, которые следует иметь в виду. Разделы этой статьи приведены ниже;

1. Загрузите и визуализируйте свои данные

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

3. Моделирование и тестирование

4. Сравнение производительности

Пойдем

1. Загрузите и визуализируйте свои данные

Импортируйте модули и библиотеки, которые будут использоваться

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
import statsmodels.tsa.api as smt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression, Ridge
from sklearn.pipeline import Pipeline
from sklearn.model_selection import TimeSeriesSplit, GridSearchCV

Загрузите свой набор данных

# Load data
df = pd.read_csv('ads.csv', parse_dates=['Time'])
df = df.set_index('Time')
df.head()

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

Расширенный тест Дики-Фуллера дает значение p 0 ‹ 0,05, это указывает на то, что ряд является стационарным и может быть смоделирован. Мы также можем заметить, что в данных присутствует 24-часовая сезонность.

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

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

Обратите внимание, что я представляю хвост набора данных, и отображаются не все функции. Я разделю данные на train-test.

# Split data into X and y
df = df.dropna()
X = df.drop(['y'], axis=1)
y = df.y

# Split data into train-test set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.33, 
shuffle=False, random_state=1)

Пункт 1

Обратите внимание, что я установил shuffle=False для сохранения последовательности информации во временном ряду, это необходимо для моделирования. Если вы работаете с данными поперечного сечения, вам не нужно беспокоиться об этом параметре.

Некоторые линейные оценки, такие как KNN, SVM и регрессионные модели, требуют преобразования функций, чтобы они имели равный диапазон перед моделированием, чтобы предотвратить доминирование функций с большим диапазоном над другими, которые могут быть не менее важными. Один из способов добиться этого — стандартизировать с помощью функции StandardScaler().

# Scale data
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)

Пункт 2

Лучший способ использовать StandardScaler() — это fit_transform(X_train) и ТОЛЬКО transform(X_test). Не fit_transform(X_test) чтобы предотвратить утечку данных, вы хотите рассматривать свой тестовый набор исключительно как невидимые данные, которые предназначены только для оценки, это даст вам реалистичную (а не оптимистическую) производительность модели.

Я подробно расскажу, как этого добиться при использовании перекрестной проверки для настройки гиперпараметров в разделе регуляризованной регрессии.

3. Моделирование и тестирование

Этот раздел будет разделен на две части — нерегулярная и регуляризованная регрессия. В нерегулярном разделе я обучу простую модель линейной регрессии без регуляризации и настройки гиперпараметров, а затем оценю ее производительность на тестовом наборе. В регуляризованном разделе я буду обучать регуляризованную регрессионную модель (регрессия Риджа), настраивать гиперпараметры в соответствии с надлежащим рабочим процессом ML и, наконец, оценивать ее производительность.

Нерегулярная модель линейной регрессии

Обучайте свою модель и делайте прогнозы

# Fit model
lr = LinearRegression()
lr_fitted = lr.fit(X_train_s, y_train)

# Make predictions
predictions_train = lr_fitted.predict(X_train_s)
predictions_test = lr_fitted.predict(X_test_s)

Задайте функцию для оценки производительности модели. Я буду использовать средневзвешенную процентную ошибку (WAPE) или отношение MAD/среднее, определенное ниже;

# Define function to evaluate model performance
def WAPE(y_true, y_pred):
    return np.mean(np.abs((y_true - y_pred) / np.mean(y_true))) * 100

Оцените производительность модели

# Evaluate model performance
train_error = WAPE(y_train, predictions_train)
test_error = WAPE(y_test, predictions_test)

print("Train set WAPE: {:.2f}%".format(train_error))
print("Test set WAPE: {:.2f}%".format(test_error))

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

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

Регулярная регрессия

Пункт 3

В дополнение к преобразованию модели регрессии требуют регуляризации, чтобы контролировать рост коэффициентов модели, тем самым предотвращая переобучение и улучшая производительность модели. Это можно сделать с помощью методов Лассо (L1), Риджа (L2) и других методов регуляризации.

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

Пункт 4

Лучший способ добиться этого — перекрестная проверка. Перекрестная проверка используется для настройки гиперпараметров, когда вы работаете с набором данных малого и среднего размера. Таким образом, модель обучается и проверяется с использованием различных разделений данных для получения наилучшего гиперпараметра. Этот метод оптимизирует производительность модели.

Важный момент, который следует учитывать при перекрестной проверке. Напомним, в пункте 2 я упомянул, что вы не делаете fit_transform(X_test) для предотвращения утечки данных и обеспечения реалистичной производительности модели. Как вы достигаете этого во время перекрестной проверки? Вам нужно относиться к своему набору проверки так, как будто это ваш набор тестов, конвейер поможет вам в этом.

Пункт 5

Конвейер поможет вам выполнить правильное масштабирование во время перекрестной проверки, не масштабируя проверочный набор (т. е. рассматривая его как тестовый набор для получения реалистичной производительности модели). Операции в пайплайн нужно добавлять последовательно — в каком порядке они должны выполняться при кросс-валидации, вы можете добавить столько операций, сколько вам нужно.

Пункт 6

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

Пункт 7

Чтобы указать стратегию разделения перекрестной проверки. Если вы работаете с временными рядами, вы можете использовать функцию TimeSeriesSplit() для сохранения последовательной информации в данных. С другой стороны, если вы работаете с данными поперечного сечения, вы можете пропустить этот шаг и установить cv=integer в объекте поиска по сетке.

Ниже представлен рабочий процесс для обучения и проверки.

# Load the data and split (unscaled)
X = df.drop(['y'], axis=1)
y = df.y
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.33, 
shuffle=False, random_state=1)

# Set up the components of the pipeline
scaler = StandardScaler()
ridge = Ridge(max_iter=10000)      

# Set up the pipeline with two steps: scale and fit
pipe = Pipeline([("scaler", scaler), ("ridge", ridge)])

# Set up the parameter grid for hyperparameter tuning during CV
param_grid = [{'ridge__alpha':[1000,500,100,50,10,5,1,.5,.1]}]

# For time-series cross-validation set 5 folds for grid search
tscv = TimeSeriesSplit(n_splits=5)

# Run grid search to find the best parameters
grid_search_object = GridSearchCV(pipe, param_grid, 
cv=tscv, scoring="neg_mean_absolute_error")   
grid_search_object.fit(X_train, y_train)     # Fit with unscaled data
best_parameters = grid_search_object.best_params_
print("best alpha: ", best_parameters['ridge__alpha'])

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

# Instantiate and fit the best ridge (using the best parameters)
best_ridge = Ridge(alpha=best_parameters['ridge__alpha'])

# Do not forget to scale the data
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)
best_ridge.fit(X_train_s, y_train)            # Scaled data

plotModelResults(best_ridge, X_train=X_train_s, X_test=X_test_s, 
y_test=y_test, plot_intervals=True, test_data=True)
plotCoefficients(best_ridge, X_train) 

predictions_train = best_ridge.predict(X_train_s)
predictions_test = best_ridge.predict(X_test_s)

# Evaluate model performance using MAD_mean ratio
train_error = WAPE(y_train, predictions_train)
test_error = WAPE(y_test, predictions_test)

print("Train set WAPE: {:.2f}%".format(train_error))
print("Test set WAPE: {:.2f}%".format(test_error))

Мы проанализируем этот результат в ближайшее время

Пункт 8

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

# Predict the test set directly from the grid search object
predictions_train = grid_search_object.predict(X_train)     
predictions_test = grid_search_object.predict(X_test)

# Evaluate model performance using MAD_mean ratio
train_error = WAPE(y_train, predictions_train)
test_error = WAPE(y_test, predictions_test)

print("Train set WAPE: {:.2f}%".format(train_error))
print("Test set WAPE: {:.2f}%".format(test_error))

Подтвердите, что мы получили тот же результат, что и создание экземпляра новой модели, простой путь!

4. Сравнение производительности

Нерегуляризованная модель показала WAPE 3,63 % на обучающем наборе и 4,73 % на тестовом наборе, в то время как регуляризованная модель показала лучшую производительность 4,12 %. strong> (обучение) и 4,34% (тест), ошибка обучения увеличилась, а ошибка теста уменьшилась (это то, что нас волнует). Коэффициенты регуляризованной модели также уменьшились по сравнению с нерегуляризованной моделью. Эти улучшения связаны с регуляризацией, предназначенной для предотвращения переобучения и повышения производительности модели на тестовом наборе с компромиссом на обучающем наборе. Самое главное, мы можем быть уверены, что получаем реалистичную производительность модели, поскольку мы использовали передовой опыт при разработке нашего рабочего процесса машинного обучения.

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

Чтобы получить комментарии или предложения по улучшению этой статьи, свяжитесь со мной на linkedin. Также ознакомьтесь с моей работой на Github. Продолжайте учиться, продолжайте писать. Увидимся в следующей статье.