Мульти-классовое целе-вероятностное кодирование (Multi-Class Target Encoding)

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Что не так с TargetEncoder из библиотеки category_encoders?

Эта статья является продолжением предыдущей статьи, в которой объяснялось, как на самом деле работает целе-вероятностное кодирование. В этой статье мы посмотрим в каких случаях стандартное решение библиотеки category_encoders дает неверный результат, а кроме того, изучим теорию и пример кода для корректного мульти-классового целе-вероятностного кодирования. Поехали!

1.   Когда ошибается TargetEncoder?

Посмотрите на эти данные. Цвет - это особенность, а цель - это… цель. Наша цель - кодировать цвет на основе Target.

Давайте сделаем для этого обычную целе-вероятностную кодировку.

import category_encoders as ce
ce.TargetEncoder(smoothing=0).fit_transform(df.Color,df.Target)

Хмм… выглядит не очень, не так ли? Все цвета были заменены на 1. Почему? Так происходит потому, что TargetEncoder принимает среднее значение всех целевых значений для каждого цвета, а не вероятность.

Хотя TargetEncoder корректно работает в случае, когда у вас есть двоичная цель, имеющая 0 и 1, он будет давать сбой в двух случаях:

  • Когда цель двоичная, но не 0/1 (хотя бы, например 1 и 2).                               

  • Когда цель - мультикласс, как в приведенном выше примере.

Так что же делать?!


Теория

В оригинальном документе Daniele Micci-Barreca, который вводит средне-целевую кодировку говориться про мульти-классовые целевые переменные.

Допустим, мы имеем n классов. Теория гласит, что первым делом нужно закодировать значения класса в бинарные переменные. Это даст n двоичных столбцов, по одному на каждый класс цели. Однако только n-1 двоичных столбцов будут линейно независимы, так что в принципе, любой из них можно отбросить. После чего применим обычное целе-вероятностное кодирование для наших новых категорий, используя каждую из двоичных меток, по одной за раз.

Давайте разберемся на примере.

Пример

Продолжим с предыдущими данными.

Шаг 1: Бинарное кодирование мульти-классовой категории.

enc=ce.OneHotEncoder().fit(df.Target.astype(str))
y_onehot=enc.transform(df.Target.astype(str))
y_onehot

Обратите внимание, что столбец Target_1 показывает наличие либо отсутствие значения 0 в исходном столбце Target. Он принимает значение 1 если в Target есть 0, либо 0 в противном случае. Точно так же столбец Target_2 показывает наличие или отсутствие 1 в Target.

Шаг 2: Кодируем цвет, используя каждую из бинарных категорий.

class_names = y_onehot.columns

for class_ in class_names: 

    enc = ce.TargetEncoder(smoothing = 0)
    print(enc.fit_transform(X,y_onehot[class_]))

Для класса 0

Для класса 1

Для класса 2

Шаг 3: Если есть другие категории, кроме цвета, повторяем шаги 1 и 2 для них.

Готово!

Таким образом, на выходе получаем такой набор данных:

Обратите внимание, что для ясности я закодировал здесь все три столбца Color_Target. Если вы знаете бинарное кодирование, то слышали, что один из столбцов можно удалить без потери информации. Следовательно, здесь мы можем безопасно удалить, например, столбец Color_Target_3 (либо какой-то другой) без потери информации.

Практика

Вы здесь за кодом, не так ли?!

Ниже представлена функция, которая принимает на вход таблицу данных и объект целевой метки типа Series. Функция df может иметь как числовые, так и категориальные переменные.

def target_encode_multiclass(X,y): #X,y are pandas df and series

    y=y.astype(str)  #convert to string to onehot encode
    enc=ce.OneHotEncoder().fit(y)
    y_onehot=enc.transform(y) 

    class_names=y_onehot.columns  #names of onehot encoded columns

    X_obj=X.select_dtypes('object') #separate categorical columns
    X=X.select_dtypes(exclude='object')

    for class_ in class_names:

        enc=ce.TargetEncoder()
        enc.fit(X_obj,y_onehot[class_]) #convert all categorical
        temp=enc.transform(X_obj)       #columns for class_
        temp.columns=[str(x)+'_'+str(class_) for x in temp.columns]
        X=pd.concat([X,temp],axis=1)    #add to original dataset

    return X

Резюме

В этой статье я показал, что не так с TargetEncoder из библиотеки category_encoder, объяснил, что говорится в оригинальной статье о целевом кодировании мультиклассовых переменных, продемонстрировал всё это на примере и предоставил рабочий модульный код, который вы можете подключить к своему приложению.

Источник: https://habr.com/ru/post/545380/


Интересные статьи

Интересные статьи

Есть способ передавать данные, теряя часть по пути, но так, чтобы потерянное можно было вернуть по прибытии. Это третья, завершающая часть моего простого изложения алгоритма избыточного к...
Все «за» и «против» 1С-Битрикс, какие есть альтернативы и что выгоднее знать разработчику? Читать далее
Всем привет. Если вы когда-либо работали с универсальными списками в Битрикс24, то, наверное, в курсе, что страница детального просмотра элемента полностью идентична странице редак...
Ваш сайт работает на 1С-Битрикс? Каждому клиенту вы даёте собственную скидку или назначаете персональную цену на товар? Со временем в вашей 1С сложилась непростая логика ценообразования и формирования...
Если в вашей компании хотя бы два сотрудника, отвечающих за работу со сделками в Битрикс24, рано или поздно возникает вопрос распределения лидов между ними.