Раз Вы смогли нагуглить эту статью, значит скорее всего знаете что такое target encoding, а тажке ознакомлены со всеми прелестями этого мощного метода и знаете все опасности переобучения, которые могут возникнуть при неправильном использовании подхода.
Поэтому здесь я приведу лишь две функции, которые можно быстро использовать для Ваших задач.
Если же не знакомы c mean encoding, то вкратце так:
На основе знаний о target, и его распределения по какой-нибудь категориальной фичи можно добавить новую переменную, показывающую характеристику встречаемости чисто внутри какой-то категории. Для примера пусть есть датасет с разными характеристиками автомобиля, необходимо предсказать город, где был куплен автомобиль. Можно подсчитать среднее кол-во каждой марки в каждом городе и добавить это как дополнительную фичу. Так скажем для тойоты это число будет больше во Владивостоке, чем для Москвы и наоборот, какой-нибудь мерседес явно будет более встречаемый в Москве, нежели рядом с Японией. Как видим, разделяемость по новой фиче будет очень хорошая. Но в этом и есть большой риск переобучения (например какая-нибудь редкая марка, которая в датасете встретится всего пару раз и в одном городе) поэтому напрямую считать среднее не рекомендуется, а правильнее будет использовать регуляризации. Ниже приведены две функции для корректного использования mean-encoding:
Функция 1: CV loop регуляризация
Достаточно интуитивный и устойчивый метод для mean encoding. Данные разбиваются на фолды и значение для каждого фолда вычисляется на основе оставшихся фолдов. Таким образом не будет переобучения на текущем куске данных, т.к. вычисляемое среднее значение будет браться на остальном подмножестве данных. Обычно 4-5 фолдов достаточно.
# Для начала создадим дата фрейм с категориальной фичей import numpy as np import pandas as pd from sklearn.model_selection import StratifiedKFold cities = ['C1', 'C1', 'C1', 'C2', 'C2', 'C3', 'C3', 'C3', 'C3', 'C3'] target = [1, 1, 0, 1, 0, 1, 1, 0, 0, 0] df = pd.DataFrame() df['cities'] = cities df['target'] = target def make_mean_encoding(df_tr, target_col_name, feature_col_name): y_tr = df_tr[target_col_name].values skf = StratifiedKFold(n_splits=2, shuffle=True, random_state=123) train_new = df_tr.copy() global_mean = df_tr[target_col_name].mean() train_new[feature_col_name + '_mean_target'] = global_mean for tr_ind, val_ind in skf.split(y_tr, y_tr): X_tr, X_val = df_tr.iloc[tr_ind], df_tr.iloc[val_ind] for col in [feature_col_name]: means = X_val[col].map(X_tr.groupby(col)[target_col_name].mean()) X_val[col + '_mean_target'] = means train_new.iloc[val_ind] = X_val # fill nan train_new.fillna(global_mean, inplace=True) return train_new df_encoded = make_mean_encoding(df, 'target', 'cities') print(df_encoded.head(10))
Функция 2: Регуляризация на основе размытия
Суть данной регуляризации в том, что мы доверяем большим категориям, с большим кол-вом значений и устанавливаем коэффициент недоверия к небольшим, слабопредставленным категориям. По сути говоря коэффициент alpha это размер группы, начиная с которой мы доверяем среднему значению
def make_mean_encoding_smooth(df_tr, target_col_name, feature_col_name): train_new = df_tr.copy() global_mean = df_tr['target'].mean() encod_type = df_tr.groupby(by=[feature_col_name], as_index=False)[target_col_name].transform(np.mean).values nrows = df_tr.groupby(by=[feature_col_name], as_index=False)[target_col_name].transform(len).values alpha = 4 train_new[feature_col_name + '_mean_target'] = (encod_type * nrows + global_mean * alpha) / (nrows + alpha) return train_new df_encoded = make_mean_encoding_smooth(df, 'target', 'cities') print(df_encoded.head(10))
Некоторые библиотеки градиентного бустинга из коробки умеют делать mean-encoding, например catboost. Делает котяра эту вещь отменно, достаточно просто указать категориальные фичи, и мне даже когда-то не хотелось лезть в эту тему, но в один момент надо было работать с очень большим датасетом, и оказалась что эта фича библиотеки ужасно прожорлива на используемую память, а если использовать ещё и обучение на видеокарте, то терабайтов оперативной памяти не хватит. Поэтому иногда полезно самим прикрутить фичи на основе mean-енкодинга, кроме того, за основу не обязательно брать таргет, можно поэкспериментировать и с другими величинами из датасета.