В продолжение темы препроцессинга категориальных переменных в 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])
Работает. Буду рад критике и замечаниям.
Комментариев нет:
Отправить комментарий