Практические руководства

Более разумные способы кодирования категориальных данных для машинного обучения

Изучение кодировщиков категорий

Лучшее кодирование категориальных данных может означать лучшую производительность модели. В этой статье я познакомлю вас с широким спектром вариантов кодирования из пакета кодировщиков категорий для использования с машинным обучением scikit-learn на Python.

TL;DR;

Используйте кодировщики категорий для повышения производительности модели, когда у вас есть номинальные или порядковые данные, которые могут дать значение.

Для номинальных столбцов попробуйте кодировку OneHot, Hashing, LeaveOneOut и Target. Избегайте OneHot для столбцов с высокой мощностью и алгоритмов на основе дерева решений.

Для порядковых столбцов попробуйте Ordinal (Integer), Binary, OneHot, LeaveOneOut и Target. Helmert, Sum, BackwardDifference и Polynomial вряд ли будут полезны, но если у вас есть время или теоретическая причина, вы можете попробовать их.

Для задач регрессии Target и LeaveOneOut, вероятно, не подойдут.

Дорожная карта

В этой статье я рассмотрю термины, общее использование и пять классических вариантов кодирования: порядковое, One Hot, двоичное, BaseN и хеширование. В будущем я могу оценить байесовские кодировщики и кодировщики контраста с корнями в проверке статистических гипотез. 🚀

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

Бесполезный - бесполезный для алгоритмов машинного обучения, то есть - дискретный
Номинальный - группы без порядка - дискретный
Двоичный - либо / или - дискретный
Порядковый - группы с порядком - дискретный
Количество - количество вхождений - дискретно
Время - циклические числа с временной составляющей - непрерывно
Интервал - положительные и / или отрицательные числа без временной составляющей - непрерывно

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

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

  1. Можно предположить, что он достаточно близок к интервальным данным - с относительно равными величинами между значениями - чтобы рассматривать их как таковые. Социологи постоянно делают это предположение с помощью шкал Лайкерта. Например, «По шкале от 1 до 7, где 1 - крайне маловероятно, 4 - ни маловероятно, ни маловероятно, а 7 - крайне вероятно, какова вероятность, что вы порекомендуете этот фильм другу?» Здесь разница между 3 и 4 и разница между 6 и 7 могут быть разумно предположены одинаковыми.
  2. Их можно рассматривать как номинальные данные, где каждая категория не имеет числового отношения к другой. Вы можете попробовать одноразовое кодирование и другие кодировки, подходящие для номинальных данных.
  3. Величиной разницы между числами можно пренебречь. Вы можете просто обучить свою модель различным кодировкам и посмотреть, какая кодировка работает лучше всего.

В этой серии мы рассмотрим кодировщики категориальных энкодеров 11, начиная с версии 1.2.8. ** Обновление: версия 1.3.0 является последней версией PyPI по состоянию на 11 апреля 2019 г. **

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

Большое спасибо Уиллу МакГиннису за создание и поддержку этого пакета. Он в значительной степени заимствован из пакета Patsy StatsModel, который, в свою очередь, основан на справочнике по статистике UCLA.

Существует бесконечное количество способов кодирования категориальной информации. Те, что в Category Encoders, должны быть достаточными для большинства применений. 👍

Краткое резюме

Вот список функций кодировщиков категорий с их описаниями и типами данных, которые они лучше всего подходят для кодирования.

Классические кодеры

Первую группу из пяти классических кодировщиков можно увидеть на континууме встраивания информации в один столбец (порядковый номер) до k столбцов (OneHot). Это очень полезные кодировки для понимания практиками машинного обучения.

Порядковый - преобразование строковых меток в целые числа от 1 до k. Порядковый.
OneHot - по одному столбцу для каждого значения для сравнения со всеми остальными значениями. Номинальный, порядковый.
Двоичный - преобразовать каждое целое число в двоичные цифры. Каждой двоичной цифре соответствует один столбец. Некоторая потеря информации, но меньше размеров. Порядковый.
BaseN - порядковый, двоичный или более высокий уровень кодировки. Именной, порядковый. Не добавляет много функциональности. Наверное, избегайте.
Хеширование - как OneHot, но меньше размеров, некоторая потеря информации из-за коллизий. Номинальный, порядковый.
Сумма - как и OneHot, за исключением того, что одно значение остается постоянным и кодируется как -1 во всех столбцах.

Контрастные энкодеры

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

Хельмерт (обратный) - среднее значение зависимой переменной для уровня сравнивается со средним значением зависимой переменной на всех предыдущих уровнях.
Обратная разница - среднее значение зависимой переменной для уровня сравнивается со средним значением зависимой переменной для предыдущего уровня.
Полином - ортогональные полиномиальные контрасты. Коэффициенты, принимаемые полиномиальным кодированием для k = 4 уровней, представляют собой линейные, квадратичные и кубические тренды в категориальной переменной.

Байесовские энкодеры

Байесовские кодировщики используют информацию из зависимой переменной в своих кодировках. Они выводят один столбец и могут хорошо работать с данными высокой мощности.

Цель - используйте среднее значение DV, необходимо предпринять шаги, чтобы избежать переобучения / утечки ответа. Именной, порядковый. Для задач классификации.
LeaveOneOut - аналогично цели, но избегает загрязнения. Именной, порядковый. Для задач классификации.
WeightOfEvidence - добавлено в версии 1.3. Не задокументировано в документации по состоянию на 11 апреля 2019 г. Метод описан в этом сообщении.
Джеймс-Штайн - ожидается в v1. 4. Описано в коде здесь.
М-оценка - ожидается в v1.4. Описано в коде здесь. Упрощенный целевой кодировщик.

Использовать

Кодировщики категорий используют тот же API, что и препроцессоры scikit-learn. У них есть некоторые дополнительные удобства, такие как возможность легко добавить кодировщик в конвейер. Кроме того, кодировщик возвращает pandas DataFrame, если ему передан DataFrame. Вот пример кода с BinaryEncoder:

В будущем мы решим несколько проблем с реализацией. Но вы сможете сразу перейти к первым пяти, если знакомы с API scikit-learn.

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

Терминология

Вы можете увидеть, что комментаторы взаимозаменяемо используют следующие термины: размер, объект, вектор, серия, независимый переменная и столбец. Я тоже буду :) Точно так же вы можете увидеть, что row и Наблюдение используются как взаимозаменяемые.

k - исходное количество уникальных значений в столбце данных. Высокая мощность означает множество уникальных значений (большое k). Столбец с сотнями почтовых индексов является примером функции высокой мощности.

Высокая размерность означает матрицу с множеством измерений. Высокая размерность сопровождается Проклятием размерности - подробное рассмотрение этой темы можно найти здесь. Вывод заключается в том, что высокая размерность требует множества наблюдений и часто приводит к переобучению.

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

Копаемся в категории энкодеров

Без лишних слов, давайте закодируем!

Порядковый

OrdinalEncoder преобразует каждое строковое значение в целое число. Первое уникальное значение в вашем столбце становится 1, второе становится 2, третье становится 3 и так далее.

Фактическое значение, которое было до кодирования, не влияет на то, каким оно становится при fit_transform с помощью OrdinalEncoder. Первым значением могло быть 10, а вторым - 3. Теперь они будут равны 1 и 2 соответственно.

Если столбец содержит номинальные данные, останавливаться после использования OrdinalEncoder - плохая идея. Ваш алгоритм машинного обучения будет рассматривать переменную как непрерывную и предполагать, что значения имеют значимый масштаб. Вместо этого, если у вас есть столбец со значениями car, bus, и truck, вы должны сначала закодировать эти номинальные данные с помощью OrdinalEncoder. Затем снова закодируйте его, используя один из методов, соответствующих номинальным данным, которые мы рассмотрим ниже.

Напротив, если значения ваших столбцов действительно порядковые, это означает, что целое число, присвоенное каждому значению, имеет смысл. Назначение должно быть сделано намеренно. Допустим, в вашем столбце есть строковые значения «Первый», «Третий» и «Второй». Эти значения должны быть сопоставлены с соответствующими целыми числами, передав OrdinalEncoder список таких слов:

[{"col": "finished_race_order", 
  "mapping": [("First", 1), 
              ("Second", 2), 
              ("Third", 3)]
}]

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

Вот непреобразованный столбец X.

А вот код OrdinalEncoder для преобразования значений столбца color из букв в целые числа.

Все строковые значения теперь целые.

OrdinalEncoder Scikit-learn делает почти то же самое, что и OrdinalEncoder Category Encoder, но не так удобен для пользователя. Кодировщик Scikit-learn не возвращает DataFrame pandas. Вместо этого он возвращает массив NumPy, если вы передаете DataFrame. Он также выводит значения, начинающиеся с 0, по сравнению с настройкой OrdinalEncoder по умолчанию для вывода значений, начинающихся с 1.

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

OneHot

Одноразовое кодирование - классический подход к работе с номинальными и, возможно, порядковыми данными. В серии учебных пособий Kaggle по машинному обучению он называется Стандартный подход к категориальным данным. Также используется кодировка имен фиктивная, индикаторная кодировка, а иногда и двоичная кодировка. Да, это сбивает с толку. 😉

Быстрый кодировщик создает один столбец для каждого значения для сравнения со всеми другими значениями. Для каждого нового столбца строка получает 1, если строка содержит значение этого столбца, и 0 в противном случае. Вот как это выглядит:

color_-1 на самом деле является лишним столбцом, потому что в нем все нули - без каких-либо изменений, он не помогает вашей модели чему-либо учиться. Возможно, он был предназначен для пропущенных значений, но в версии 1.2.8 Category Encoders он не служит цели.

Быстрое кодирование может работать очень хорошо, но количество новых функций равно k количеству уникальных значений. Это расширение функций может создать серьезные проблемы с памятью, если ваш набор данных имеет функции высокой мощности. Однократное горячее кодирование данных также может быть затруднительным для алгоритмов на основе дерева решений - см. Обсуждение здесь.

Функции pandas GetDummies и scikit-learn OneHotEncoder выполняют ту же роль, что и кодировщики категорий OneHotEncoder. Я считаю, что кодировщики категорий OneHotEncoder немного удобнее в использовании.

Двоичный

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

Вот как это работает:

  • Категории кодируются OrdinalEncoder, если они еще не представлены в числовой форме.
  • Затем эти целые числа преобразуются в двоичный код, например, 5 становится 101, а 10 становится 1010.
  • Затем цифры из этой двоичной строки разбиваются на отдельные столбцы. Таким образом, если в порядковом столбце 4–7 значений, создаются 3 новых столбца: один для первого бита, один для второго и один для третьего.
  • Каждое наблюдение кодируется по столбцам в двоичной форме.

Вот как это выглядит:

В первом столбце нет дисперсии, поэтому он не помогает модели.

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

Напротив, двоичный файл действительно эффективен, когда количество элементов столбца выше - например, в 50 штатах США.

При двоичном кодировании создается меньше столбцов, чем при однократном кодировании. Это более эффективно с точки зрения памяти. Это также снижает вероятность проблем размерности с более высокой мощностью.

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

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

BaseN

Когда BaseN base = 1, это в основном то же самое, что и одно горячее кодирование. Когда base = 2, это в основном то же самое, что и двоичное кодирование. МакГиннис сказал об этом кодировщике: На практике это добавляет очень мало новых функций, люди редко используют базу 3 или 8 или любую другую, кроме порядковой или двоичной, в реальных задачах.

Основная причина существования BaseN - облегчить поиск по сетке. Вы можете использовать BaseN с G ridSearchCV из scikit-learn. Однако , если вы собираетесь выполнять поиск по сетке с этими параметрами кодирования, вы можете сделать кодировщик частью конвейера scikit-learn и поместить параметры в сетку параметров. Я не вижу веских причин использовать BaseN. Если да, поделитесь в комментариях.

Базой по умолчанию для BaseNEncoder является 2, что эквивалентно BinaryEncoder.

Хеширование

HashingEncoder реализует трюк с хешированием. Это похоже на однократное кодирование, но с меньшим количеством новых измерений и некоторой потерей информации из-за коллизий. Коллизии не оказывают существенного влияния на производительность, если только нет большого перекрытия. Отличное обсуждение трюка с хешированием и рекомендации по выбору количества выходных функций можно найти здесь.

Снова порядковый столбец, чтобы напомнить.

А вот и HashingEncoder с выводом.

Параметр n_components управляет количеством развернутых столбцов. По умолчанию восемь столбцов. В нашем примере столбец с тремя значениями по умолчанию получается пять столбцов, заполненных нулями.

Если вы установите n_components меньше, чем k, вы получите небольшое уменьшение значения, обеспечиваемого закодированными данными. У вас также будет меньше размеров.

Вы можете передать алгоритм хеширования по вашему выбору в HashingEncoder; по умолчанию - md5. Алгоритмы хеширования были очень успешными в некоторых соревнованиях Kaggle. Стоит попробовать HashingEncoder для номинальных и порядковых данных, если у вас есть функции высокой мощности. 👍

Сворачивать

На этом пока все. Вот краткий обзор и предложения о том, когда использовать кодировщики.

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

Для порядковых столбцов попробуйте Ordinal (Integer), Binary, OneHot, LeaveOneOut и Target. Helmert, Sum, BackwardDifference и Polynomial вряд ли будут полезны, но если у вас есть время или теоретическая причина, вы можете попробовать их.

Байесовские кодировщики могут хорошо работать для некоторых задач машинного обучения. Например, Оуэн Чжан использовал метод кодирования с исключением одного выхода, чтобы хорошо справиться с задачей классификации Kaggle.

* Обновление, апрель 2019 г .: я обновил эту статью, включив в нее информацию о будущих кодировщиках, и переработал вывод. **

Я пишу о науке о данных, Python, SQL и DevOps. Ознакомьтесь с другими моими статьями и подпишитесь на меня здесь, если вам это нравится. 😀

Спасибо за прочтение!