Обработка цикличных признаков
Отдельные числовые признаки, несмотря на обработку моделями машинного обучения, зачастую все же нуждаются в преобразованиях. Одним из примеров являются номера месяцев, часов, минут и т.д, никак не отражающие цикличный характер признаков. Чтобы это исправить, обычно используют функции синуса и косинуса, имеющие период в 2пи. Для преобразования понадобится отобразить числовые значения как-то так:
Для примера сгенерируем датасет с примерными средними температурами по месяцам:
import pandas as pd import numpy as np np.random.seed(5) temp_avg_d = {1:0, 2:-2, 3:15, 4:20, 5:25, 6:28, 7:30, 8:27, 9:20, 10:12, 11:7, 12: 2} mon_ar = np.tile(np.arange(1, 13), 3) ts = pd.DataFrame({'mon':mon_ar}) ts['t'] = ts['mon'].map(lambda x:temp_avg_d[x] + np.random.normal(loc=0, scale=2)) ts.head()
Разобьем датасет на тренировочную и валидационную части:
from sklearn.model_selection import train_test_split X_tr, X_val, y_tr, y_val = train_test_split(ts.drop(columns='t'), ts['t'])
Теперь попытаемся предсказать температуру по месяцу:
from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_absolute_error model = LinearRegression() model.fit(X_tr, y_tr) mean_absolute_error(y_val, model.predict(X_val))
Можно заметить, что модель с такой интерпретацией месяца практически не улавливает сезонный характер температуры (абсолютная ошибка в 11 градусов!):
pd.DataFrame({'mon':X_val['mon'], 'pred':model.predict(X_val), 'y':y_val})
Теперь отобразим номер месяц в синус и косинус аналогично правилу выше:
ts_ext = ts.copy() ts_ext['mon_sin'] = np.sin(2*np.pi*ts['mon']/ts['mon'].max()).round(2) ts_ext['mon_cos'] = np.cos(2*np.pi*ts['mon']/ts['mon'].max()).round(2) ts_ext.head()
Посчитаем регрессию по двум новым признакам:
tr_index = X_tr.index val_index = X_val.index model = LinearRegression() model.fit(ts_ext.drop(columns=['t', 'mon']).loc[tr_index], y_tr) mean_absolute_error(y_val, model.predict(ts_ext.drop(columns=['t', 'mon']).loc[val_index]))
Как можно заметить, новая модель гораздо лучше справляется с предсказаниями:
pd.DataFrame({'mon':ts_ext['mon'].loc[val_index], 'y':y_val, 'pred':model.predict(ts_ext.drop(columns=['t', 'mon']).loc[val_index])})