машинное обучение
December 22, 2022

Dummy модель своими руками

Для оценки реального качества работы модели машинного обучения в качестве точки отсчета (baseline) используют простые алгоритмы. Рассмотрим, способы их правильного создания для гармоничной работы со средствами обработки данных в библиотеке scikit-learn. Сначала создадим демонстрационный датафрейм:

import pandas as pd
import numpy as np
np.random.seed(0)

df = pd.DataFrame(np.random.normal(size=(10,3)), columns=['val1', 'val2', 'val3'])
df['target'] = df['val3']
df

Сымитируем разделение датасета на тренировочный и тестовый:

from sklearn.model_selection import train_test_split

X_tr, X_ts, y_tr, y_ts = train_test_split(df.drop(columns='target').copy(), 
                                          df['target'], test_size=0.2)
y_tr.shape[0], y_ts.shape[0]

Напишем простой класс, позволяющий предсказывать цель (target) по ее средним значениям в предыдущих периодах (val1, val2, val3). Для его совместимости с использующими модели методами и пайплайнами надо сделать класс наследником BaseEstimator из sklearn.base и реализовать методы fit и predict:

from sklearn.base import BaseEstimator

class HorisontalDummyRegressor(BaseEstimator):
    
    def __init__(self, calc_cols, strategy='mean'):
        self.calc_cols = calc_cols
        self.strategy = strategy
    
    def fit(self, X_tr, y_tr):
        return self

    def predict(self, X_ts):
        if self.strategy == 'mean':
            return X_ts[self.calc_cols].mean(axis=1)
        if self.strategy == 'median':
            return X_ts[self.calc_cols].median(axis=1)
            

Приведем пример стандартного использования класса, когда предсказание строится по копии заданной колонки (val2):

reg = HorisontalDummyRegressor(['val2'])

reg.fit(X_tr, y_tr)
reg.predict(X_ts)

Как и ожидалось, предсказания совпадают с 'val2':

X_ts['val2']

Так как мы сделали класс наследником BaseEstimator, можем передать его в cross_val_score:

from sklearn.model_selection import cross_val_score

cross_val_score(reg, X_ts, y_ts, scoring='neg_mean_absolute_error', cv=2)

Для удобства сверки правильности результатов запустили cross_val_score на X_ts, y_ts (хотя в данном случае правильно кросс-валидацию проводить по train выборке):

-(X_ts['val2']- y_ts).abs()

Теперь сравним предсказания на всем X_ts с разными стратегиями и полученными вручную значениями:

reg1 = HorisontalDummyRegressor(['val1', 'val2', 'val3'])
reg2 = HorisontalDummyRegressor(['val1', 'val2', 'val3'], strategy = 'median')
reg3 = HorisontalDummyRegressor(['val1'])

X_ts['y_mean'] = reg1.predict(X_ts)
X_ts['y_median'] = reg2.predict(X_ts)
X_ts['y_copy'] = reg3.predict(X_ts)
X_ts
X_ts[['val1','val2', 'val3']].agg(['mean', 'median'], axis=1)

Наши модели поддерживают и метод cross_val_predict, вот, например, медианный прогноз (reg2) с cross_val_predict:

from sklearn.model_selection import cross_val_predict

cross_val_predict(reg2, df.drop(columns='target'), df['target'])