В продолжение темы препроцессинга категориальных переменных в sklearn pipeline Python.
См. также пост Препроцессинг категориальных переменных в sklearn pipeline Python с LabelEncoder.
Т.е. предыдущий пост про технику препроцессинга на основе LabelEncoder, а в данном посте я покажу, как работаю с LeaveOneOutEncoder.
LeaveOneOutEncoder пожалуй самый необычный способ препроцессинга категориальных переменных.
LeaveOneOutEncoder считается очень удобным, когда у вас много (от нескольких десятков до нескольких сотен) уровней фактора, а также когда часть уровней фактора очень немногочисленны. В моей практике самый лучший пример - уровень зарплат по регионам. У нас 89 регионов в России, причем, львиная доля приходится на Москву, меньше на Санкт-Петербург, а потом уже на остальные регионы, а на некоторые приходится совсем единицы.
См. также пост Препроцессинг категориальных переменных в sklearn pipeline Python с LabelEncoder.
Т.е. предыдущий пост про технику препроцессинга на основе LabelEncoder, а в данном посте я покажу, как работаю с LeaveOneOutEncoder.
LeaveOneOutEncoder пожалуй самый необычный способ препроцессинга категориальных переменных.
LeaveOneOutEncoder считается очень удобным, когда у вас много (от нескольких десятков до нескольких сотен) уровней фактора, а также когда часть уровней фактора очень немногочисленны. В моей практике самый лучший пример - уровень зарплат по регионам. У нас 89 регионов в России, причем, львиная доля приходится на Москву, меньше на Санкт-Петербург, а потом уже на остальные регионы, а на некоторые приходится совсем единицы.
Пример
У нас есть такой датасетdf= pd.DataFrame({ 'y': [10,2,3,4,5,6,7,8], 'a': [np.nan, 'b','a', 'b','a', 'b','a', 'b' ], 'c': ['a', 'b','a', 'b','a', 'b','b', 'b' ]})Где y - целевая переменная, которую мы предсказываем, а a, c - категориальные переменные, на основе которых мы прогнозируем y.
После препроцессинга по методу LeaveOneOutEncoder категориальные переменные принимают такой вид
0 1 0 5.625 6.0 1 5.000 5.4 2 5.000 6.0 3 5.000 5.4 4 5.000 6.0 5 5.000 5.4 6 5.000 5.4 7 5.000 5.4Вы еще не знакомы с техникой препроцессинга категориальных переменных по методу LeaveOneOutEncoder? После препроцессинга переменные становятся типа numeric, т.е. из категориальных превращаются в числовые.
LeaveOneOutEncoder - это среднее по каждому уровню фактора. Возьмем переменную c. Уровню переменной a соответствуют значения целевой переменной Y 10, 3 и 5. Среднее значение по ним равно (10+3+5)/3 = 6. Таким образом, в категориальной переменной с уровень a принимает значение 6.0. А если у нас уровень пропущен, т.е поле пустое, то оно принимает значение среднего по всем данным. В переменной a есть пропущенное значение (np.nan), после препроцессинга оно принимает значение 5.625. Оно получается как среднее значение по всем переменным: (10+2+3+4+5+6+7+8)/8=5.625.
Простой код препроцессинга
lb = df[['a', 'c']] enc = LeaveOneOutEncoder() encc = enc.fit(np.asarray(lb), df['y']) enc_data = enc.transform(np.asarray(lb)) enc_dataОбратите внимание, в команде fit у нас участвует целевая переменная. И поэтому код для pipeline у нас будет немного отличаться от того, что мы делали, например, для LabelEncoder.
LeaveOneOutEncoder в в sklearn pipeline Python
загружаем необходимые пакетыimport pandas as pd import numpy as np from sklearn import preprocessing import sklearn from sklearn.pipeline import Pipeline from sklearn.pipeline import FeatureUnion from category_encoders import LeaveOneOutEncoder from sklearn import linear_modelToy датасет
df= pd.DataFrame({ 'y': [10,2,3,4,5,6,7,8], 'a': [np.nan, 'b','a', 'b','a', 'b','a', 'b' ], 'c': ['a', 'b','a', 'b','a', 'b','b', 'b' ], 'b': [5,5,3,4,8,6,7,3],})Я добавил еще переменную b только для того, чтобы показать, что мы можем брать в препроцессинг любое количество переменных. И декларируем формулу по выбору этим переменных
class MultiColumn(): def __init__(self,columns = None): self.columns = columns # array of column names to encode def fit(self,X,y=None): return self def transform(self, X): return X[self.columns]Теперь объект class для препроцессинга категориальных переменных с помощью LeaveOneOutEncoder.
lb = df[['a', 'c']] class MyLEncoder(BaseEstimator, TransformerMixin): def transform(self, X, **fit_params): enc = LeaveOneOutEncoder() encc = enc.fit(np.asarray(lb), y) enc_data = encc.transform(np.asarray(X)) return enc_data def fit_transform(self, X,y=None, **fit_params): self.fit(X,y, **fit_params) return self.transform(X) def fit(self, X, y, **fit_params): return self
На самом деле все просто. И выходим на pipeline
X = df[['a', 'b', 'c']] y = df['y'] regressor = linear_model.SGDRegressor() pipeline = Pipeline([ ('union', FeatureUnion( transformer_list=[ # categorical ('categorical', Pipeline([ ('selector', MultiColumn(columns=['a', 'c'])), ('one_hot', MyLEncoder()) ])), ])), # Use a regression ('model_fitting', linear_model.SGDRegressor()), ]) pipeline.fit(X, y)Делаем predict на нашем датасете.
pipeline.predict(X) array([5.49996715, 4.92702859, 5.19722919, 4.92702859, 5.19722919, 4.92702859, 4.92702859, 4.92702859])
Но в нашем случае нужно обязательно проверить, что препроцессинг категориальных переменных в sklearn pipeline Python с помощью LeaveOneOutEncoder работает на новом датасете.
Создаем его и проверяем.
new= pd.DataFrame({ 'y': [3, 8], 'a': ['a', 'b' ],'c': ['b', 'a' ], 'b': [3, 6],}) pipeline.predict(new) array([4.92702859, 5.19722919])Работает. Буду рад критике и замечаниям.
Комментариев нет:
Отправить комментарий