Категориальные Особенности

Не только One-Hot.




Привет, хабр! Хотелось бы сделать небольшой экскурс по работе с категориальными характеристиками, на которую в Интернете часто не обращают внимания.

В этой статье я постараюсь расширить основные понятия по этой теме и проиллюстрировать их примерами.

Под категориальные данные Мы понимаем данные, которые не имеют числового представления; он может иметь два уникальных значения (бинарные функции) или более.

Для работы со знаками необходимо сделать кодирование категориальных признаков - процедура, представляющая собой некоторое преобразование категориальных признаков в числовое представление в соответствии с некоторыми ранее заданными правилами.

Для меня эта тема очень щекотлива, потому что на большинстве курсов DS ей либо вообще не уделяют внимания, либо уделяют этому недостаточно времени.






Почему это необходимо?

Как мы знаем из теории, для корректной работы простых линейных моделей мы должны передавать только числовые характеристики, поэтому для них необходимость подобных преобразований (категориальная характеристика -> некоторое числовое представление) просто необходима! Однако, опять же, возвращаясь к теории, мы знаем, что Деревья решений могут работать с необработанными категориальными признаками, но на практике происходит следующее: Попробуем обучить дерево решений задачи.

бинарная классификация в реализации sklearn (из модуля дерева) на наборе данных игрушки:

  • Импортируем метод DecisionTreeClassifier из sklearn.tree и, конечно же, загружаем pandas:
  
  
  
  
  
  
  
  
  
  
  
  
  
   

import pandas as pd from sklearn.tree import DecisionTreeClassifier

  • Далее давайте создадим игрушечный набор данных.



data = pd.DataFrame() data['A'] = ['a','a','b','a'] data['B'] = ['b','b','a','b'] data['Class'] = [0, 0, 1, 0]



Категориальные особенности

результат выполнения кода
  • Обучим модель:


tree = DecisionTreeClassifier() tree.fit(data[['A','B']], data['Class'])



Категориальные особенности

результат выполнения кода
Мы видим ValueError, который говорит нам, что нам нужно подать на вход реализации в sklearn строго числовые характеристики!
Таким образом, мы обосновали трансформацию даже для тех моделей, которые теоретически могут работать с необработанными категориальными признаками.






Что такое категориальные кодеры?

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

Прежде всего, мы разберем самые популярные из них – Кодировщики Label и One-Hot.

Кодировщик этикеток

Этот тип кодирования используется наиболее часто; преобразование представляет собой взаимно однозначное соответствие между числом <-> уникальное значение категориального признака.

Первое (каким-то образом выбранное) уникальное значение кодируется как ноль, второе как единица и так далее, последнее кодируется числом, равным количеству уникальных значений минус один.

Давайте посмотрим на пример:
  • Предположим, у нас есть категориальный атрибут марки автомобиля со значениями BMW, Mercedes, Nissan, Infinity, Audi, Volvo, Skoda.
  • Давайте создадим искусственный атрибут бренда и закодируем его с помощью реализации sklearn.


data = pd.DataFrame() data['brand'] = ['BMW', 'Mercedes', 'Nissan', 'Infinity', 'Audi', 'Volvo', 'Skoda']*5

  • Для чистоты эксперимента смешаем наши данные с помощью метода sample(), исправим rand_state для воспроизводимости и посмотрим на заголовок данных:


data = data.sample(frac=1,random_state=42).

reset_index(drop=True) data.head(10)



Категориальные особенности

результат выполнения кода

  • Давайте применим Label Encoder:


from sklearn.preprocessing import LabelEncoder labelencoder = LabelEncoder() data_new = labelencoder.fit_transform(data.values) data_new[:10]



Категориальные особенности

результат выполнения кода
  • Давайте посмотрим на «правило трансформации» с помощью метода groups_.


labelencoder.classes_



Категориальные особенности

результат выполнения кода
Реализация Label Encoder в sklearn сначала сортирует уникальные значения по алфавиту, а затем присваивает им порядковый номер!
Давайте поговорим о Основным недостатком Label Encoder является создание избыточных зависимостей данных.

После преобразования выяснилось, что для этой характеристики Volvo имеет числовое значение 6, а для BMW — числовое значение 1, что дает Мы имеем право сказать, что Volvo в 6 раз крупнее (круче и т. д.) BMW по бренду.

Однако в исходных данных таких зависимостей не было, что является существенным недостатком данного варианта кодирования.



One-Hot Encoder

Этот тип кодирования основан на создании двоичных признаков, указывающих на принадлежность к уникальному значению.

Проще говоря, используя наш атрибут бренда в качестве примера, мы создаем двоичные атрибуты для всех уникальных значений: Brand_Volvo, Brand_BMW, .

, где атрибут бренда Volvo Brand_Volvo имеет значение 1, если объект в атрибуте бренда имеет значение Volvo и ноль для всех остальных.

Давайте рассмотрим пример атрибута бренда:

from sklearn.preprocessing import OneHotEncoder onehotencoder = OneHotEncoder() data_new = onehotencoder.fit_transform(data.values) pd.DataFrame(data_new.toarray(), columns=onehotencoder.categories_).

head(10)



Категориальные особенности

результат выполнения кода Основным недостатком One-Hot Encoder является значительное увеличение объема данных, поскольку признаки с большим количеством уникальных значений кодируются большим количеством двоичных признаков.

Label Encoder и One-Hot Encoder включены в библиотеку sklearn. В библиотеке представлены следующие кодеры категория_энкодеры !


Двоичный кодировщик

Для решения проблемы One-Hot Encoding с размером пространства, получаемого после кодирования, была предложена идея, использующая принцип преобразования десятичных чисел в двоичное представление.

Принцип трансляции заключается в том, что десятичное число N может быть представлено log(N), где log — логарифм по основанию 2, двоичными значениями, принимающими значения {0,1}.

Например, число 22 можно представить как 10110, т.е.

5 бит.

Давайте тогда сформулируем идею кодирования.

Предположим, у нас есть N уникальных значений категориального признака, тогда мы можем его закодировать, используя не N двоичных признаков, а просто войдите (N), представление порядкового номера уникального значения в виде строки двоичного представления.

Вернемся к примеру с брендом.

Итак, у нас всего 7 уникальных значений, тогда для этого типа кодирования достаточно 3 знаков вместо 7. Тогда Volvo (первое уникальное значение в знаке, порядковый номер 1, в двоичном формате 001) будет закодировано как [0, 0,1].

Обратите внимание, что в Binary Encoder уникальные значения никак не сортируются, т.е.

то, что в данных было первым, будет закодировано меньшим порядковым номером! Кодировка зависит от расположения строк в данных!

  • Давайте посмотрим на трансформацию:


!pip install category_encoders from category_encoders.binary import BinaryEncoder

  • Вызов как в sklearn:


bn = BinaryEncoder() bn.fit_transform(data.values)[:10]



Категориальные особенности

результат выполнения кода Основная проблема этого подхода заключается в том, что в стремлении к оптимизации количества признаков после преобразования теряется интерпретируемость бинарных признаков, характерная для функций One-Hot Encoder. Далее, чтобы не затягивать рассказ, опишем оставшиеся две группы категориальных кодеров, о которых вы вряд ли слышали раньше: контрастные и целевые кодеры.



Контрастное кодирование

По своей сути контрастные кодеры можно назвать гибридом двоичных кодеров и кодеров One-Hot. Они являются «гибридом», потому что они, как и One-Hot Encoder, кодируют N уникальных функций с помощью нескольких функций, точнее N-1 функции, но они не являются двоичными! Эти знаки обычно называют фиктивные переменные .

Давайте посмотрим на пример кодировщика Хелмерта и кодировщика обратной разности:

  • Кодер Хелмерта кодирует по следующему принципу: N признаков кодируются матрицей (N, N-1), где на главной диагонали матрицы и выше нее находятся единицы со знаком минус, а непосредственно под главной диагональю находится порядковый номер значения, а под ним нули.

Важным моментом является то, что при кодировании Helmert Encoder сортировка происходит при кодировании уникальных значений!
Для наглядности давайте закодируем отсортированный список уникальных значений, а затем посмотрим, как он будет выглядеть в данных.



from category_encoders.helmert import HelmertEncoder he = HelmertEncoder(drop_invariant=True) he.fit_transform(sorted(['BMW', 'Mercedes', 'Nissan', 'Infinity', 'Audi', 'Volvo', 'Skoda'])) ['Audi', 'BMW', 'Infinity', 'Mercedes', 'Nissan', 'Skoda', 'Volvo']



Категориальные особенности

результат кодирования, индекс соответствует индексу в списке комментариев Тогда кодировка всех данных будет следующей:

he = HelmertEncoder(drop_invariant=True) he.fit_transform(data.values)[:10]



Категориальные особенности

результат выполнения кода

  • Кодер обратной разности кодирует категориальные данные по схеме, аналогичной Helmert Encoder, т.е.

    с разницей до и после главной диагонали.

    Здесь легче увидеть иллюстрацию кодирования категориального признака с N=4 уникальными значениями k = N-1 = 3 фиктивными признаками.



Категориальные особенности

кодирование функции с 4 значениями Давайте посмотрим на кодирование атрибута нашего бренда, сначала на отсортированных уникальных значениях, затем на всех данных:

from category_encoders.backward_difference import BackwardDifferenceEncoder bd = BackwardDifferenceEncoder(drop_invariant=True) bd.fit_transform(sorted(['BMW', 'Mercedes', 'Nissan', 'Infinity', 'Audi', 'Volvo', 'Skoda']))



Категориальные особенности

результат выполнения кода

bd = HelmertEncoder(drop_invariant=True) bd.fit_transform(data.values)[:10]



Категориальные особенности

результат выполнения кода

Целевое кодирование

Основная цель этого типа кодировщика — использование целевой метки для кодирования категориальные черты.

Целевые кодировщики включают целевой кодировщик, кодировщик с исключением одного и кодировщик Джеймса-Стейна.

Target Encoder реализован «под капотом» в модели повышения градиента по деревьям решений.

CatBoost !

  • Целевой кодировщик для задачи регрессии использует среднее целевое значение для данного значения категориального атрибута.

Другими словами, если у нас есть задача спрогнозировать цену автомобиля, целевой меткой является цена автомобиля, то каждое значение марки автомобиля в нашем атрибуте бренда кодируется средней ценой автомобиля этой марки.

.

  • Целевой кодировщик для задачи двоичной классификации использует вероятность одного класса для заданного значения категориального признака.

Другими словами, если у нас есть задача спрогнозировать цену продажи автомобиля (проданного/не проданного), класс единицы – это успешная продажа автомобиля, то каждое значение марки автомобиля в нашем атрибуте бренда кодируется вероятность продажи автомобиля.

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

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

  • Кодировщик с исключением одного является расширением Target Encoder, в котором кодирование конкретный объект обучающей выборки производится с использованием расчета среднего значения/вероятности одного класса без учета стоимости этого объекта (т.е.

    мы просто удаляем его значение, отсюда и название кодировщика).

    Для проба ничем не отличается от Targer Encoder.

  • Кодировщик Джеймса-Стейна это какой-то средневзвешенное между значения для заданного значения категориального признака и значения для всей выборки .

    Важным моментом является тот факт, что из формул для веса B можно сказать, что данный кодер и его оптимальный параметр B определяется правильно и однозначно в случае, когда целевая метка нормально распределена !

Кодировщик Джеймса-Стейна предназначен только для задач регрессии!


Категориальные особенности

формулы для определения значения коэффициента Джеймса-Стейна энкодера




Полученные результаты

В этой статье мы познакомили вас с различными методами кодирования категориальных признаков и узнали плюсы и минусы их использования.

Надеюсь, эта информация будет полезна как новичкам в ДС, так и опытным специалистам.

В этой теме мы рассмотрели важный метод кодирования — хеширование и основанный на нем трюк хеширования, о котором я постараюсь рассказать в будущих статьях.

Материал и код подготовил: Андрей Дзис, канал в ТГ @dzis_science.


Материал защищен авторским правом.

Копирование и использование материалов возможно только с согласия автора со ссылкой на источник.

Теги: #python #ml #Инженерия данных #Интеллектуальный анализ данных #категорические функции #предварительная обработка #энкодер

Вместе с данным постом часто просматривают: