June 27, 2022

Частотное кодирование факторных колонок

Важной задачей при построении моделей машинного обучения является перевод факторных колонок в числа. Наиболее частым способом является one-hot энкодинг, о котором я рассказывал ранее. В случае большого количества категорий такой способ может привести к переобучению модели, поэтому рассматривают другие приемы. При этом прибегают как к использованию грубых путей как порядковое кодирование, так и попыткам ухватит дополнительную информацию, которую могут нести категории. В частности, ею может быть абсолютная или относительная частота встречаемости значений колонки. Для демонстрации работы частотного кодирования рассмотрим датафреймы:

import pandas as pd
import numpy as np

df_train = pd.DataFrame([['fourth_cat1', 'third_cat2', 1], 
                         ['first_cat1', 'third_cat2', 1], 
                         ['second_cat1', 'third_cat2', 2], 
                         ['second_cat1', 'second_cat2', 5],
                        ['second_cat1', None, 5]])

df_valid = pd.DataFrame([['fifth_cat1', 'third_cat2', np.nan], 
                        ['second_cat1', 'third_cat2', 2], 
                        ['second_cat1', 'second_cat2', 2]])

Сначала создадим собственный преобразователь (о том, как подробнее рассказывал здесь):

from sklearn.base import TransformerMixin, BaseEstimator

class FreqEncoding(TransformerMixin, BaseEstimator):
    freq_d = {}
    
    def fit(self, X):
        for col in X.select_dtypes(include=['category', 'object']).columns:
            self.freq_d[col] = X[col].value_counts(normalize=True).to_dict()
        return self
    
    def transform(self, X):
        X_tr = X.copy()
        for col in X_tr.select_dtypes(include=['category', 'object']).columns:
            X_tr[col] = X_tr[col].map(lambda x: self.freq_d[col].get(x, 0), na_action='ignore')
        return X_tr
    

Сначала вызовем fit_transform для обучения и преобразования df_train:

enc = FreqEncoding()
enc.fit_transform(df_train)

А теперь transform для преобразования df_valid:

enc.transform(df_valid)

Ниже привожу словарь с частотами категорий, сформированный в ходе обучения на df_train:

enc.freq_d

Теперь вызовем pipeline предобработки данных с нашим классом:

from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer

tr = Pipeline(steps=[('freq', FreqEncoding()),('imp', SimpleImputer())])
tr.fit_transform(df_train)
tr.transform(df_valid)

Следует отметить, что в библиотеке category_encoders с реализованными энкодерами, пока не включенными в sklearn, имеется рассматриваемый в данной статье frequency encoder, который называется CountEncoder. Конечно, его функционал шире, реализованного нами FreqEncoding (например, можно выбирать нормализуются ли частоты с параметром normalize, есть обработка Nan значений):

import category_encoders as ce
enc = ce.CountEncoder(normalize=True)

enc.fit_transform(df_train)
enc.transform(df_valid)

Как можно догадаться, CountEncoder также поддерживается в pipeline-ах:

from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer

tr = Pipeline(steps=[('freq', ce.CountEncoder(normalize=True)),('imp', SimpleImputer())])
tr.fit_transform(df_train)
tr.transform(df_valid)

Полезные ссылки:

  1. Создание пользовательских преобразователей данных
  2. Порядок обучения и запуска преобразователей данных
  3. Бинарное кодирование
  4. One-hot кодирование
  5. Порядковое (Ordinal) кодирование

Не пропустите ничего интересного и подписывайтесь на страницы канала в других социальных сетях:

Яндекс Дзен

Telegram