строки как объекты в дереве решений / случайном лесу

64

Я делаю некоторые проблемы с применением дерева решений / случайного леса. Я пытаюсь приспособить проблему, в которой в качестве функций есть цифры, а также строки (например, название страны). Теперь библиотека scikit-learn принимает только числа в качестве параметров, но я хочу ввести строки, так как они несут значительный объем знаний.

Как мне справиться с таким сценарием?

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

user3001408
источник
В случае sckitlearn я видел, что нам нужно кодировать категориальные переменные, иначе метод fit выдаст ошибку, сообщающую ValueError: не удалось преобразовать строку в число с плавающей точкой
Kar

Ответы:

56

В большинстве устоявшихся систем машинного обучения категориальные переменные обрабатываются естественным образом. Например, в R вы будете использовать коэффициенты, в WEKA вы будете использовать номинальные переменные. Это не так в scikit-Learn. Деревья решений, реализованные в scikit-learn, используют только числовые функции, и эти функции всегда интерпретируются как непрерывные числовые переменные .

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

Одним из примеров является кодирование ['red', 'green', 'blue'] с помощью [1,2,3], которое может привести к странным вещам, например, что 'red' ниже, чем 'blue', и если вы усредните 'red' и «синий» вы получите «зеленый». Еще один более тонкий пример может возникнуть, когда вы кодируете ['low', 'medium', 'high'] с помощью [1,2,3]. В последнем случае может иметь место упорядочение, которое имеет смысл, однако могут возникнуть некоторые тонкие несоответствия, когда «средний» находится не в середине «низкого» и «высокого».

Наконец, ответ на ваш вопрос заключается в кодировании категориальной функции в несколько бинарных функций . Например, вы можете написать ['red', 'green', 'blue'] с 3 столбцами, по одному для каждой категории, с 1, когда категория соответствует, и 0 в противном случае. Это называется горячим кодированием , двоичным кодированием, кодированием по одному или любому другому. Вы можете проверить документацию здесь для кодирования категориальных функций и извлечения функций - хеширования и диктовок . Очевидно, что горячее кодирование расширит ваши требования к пространству, а иногда и ухудшает производительность.

rapaio
источник
2
Это реализация Scikit, которая не обрабатывает категориальные переменные должным образом. Перекодирование, подобное тому, что предлагает этот ответ, вероятно, лучшее, что вы можете сделать. Более серьезный пользователь может искать альтернативный пакет.
SmallChess
3
Можно использовать sklearn.preprocessing.LabelBinarizer для горячего кодирования категориальной переменной.
GuSuku
@ rapaio Я думаю, что двоичное кодирование - это не то же самое, что горячее кодирование. Бинарное кодирование - это когда вы представляете 8 категорий с 3 столбцами или от 9 до 16 категорий с 4 столбцами и т. Д. Я ошибаюсь?
Alok Nayak
пакет pysy python будет иметь дело с горячим кодированием категориальных переменных. patsy.readthedocs.io/en/latest/quickstart.html
zhespelt
5
Не используйте LabelBinarizer, используйте sklearn.preprocessing.OneHotEncoder . Если вы используете pandas для импорта и предварительной обработки ваших данных, вы также можете сделать это напрямую, используя pandas.get_dummies . Это отстой, что scikit-learn не поддерживает категориальные переменные.
Рикардо Круз
11

Вам необходимо закодировать ваши строки в виде числовых функций, которые Sci-Kit может использовать для алгоритмов ML. Эта функциональность обрабатывается в модуле предварительной обработки (например, см. Sklearn.preprocessing.LabelEncoder для примера).

Кайл.
источник
4
Рапайо объясняет в своем ответе, почему это приведет к неверному результату
Кит
7

Обычно вы должны однозначно кодировать категориальные переменные для моделей scikit-learn, включая случайный лес. Случайный лес часто работает нормально без кодирования в одно касание, но обычно работает лучше, если вы выполняете кодирование в одно касание. Переменные «горячего кодирования» и «пустышки» означают одно и то же в этом контексте. Scikit-learn имеет sklearn.preprocessing.OneHotEncoder, а у Pandas есть pandas.get_dummies для этого.

Однако есть альтернативы. Статья «Beyond One-Hot» в KDnuggets прекрасно объясняет, почему вам нужно кодировать категориальные переменные и альтернативы кодированию в одно касание.

Существуют альтернативные реализации случайного леса, которые не требуют одноразового кодирования, такие как R или H2O. Реализация в R является вычислительно дорогой и не будет работать, если ваши функции имеют много категорий . H2O будет работать с большим количеством категорий. Континуум сделал H2O доступным в Anaconda Python.

Существует постоянные усилия , чтобы сделать scikit-Learn обрабатывать категориальные особенности непосредственно .

Эта статья объясняет алгоритм, используемый в H2O. Он ссылается на академический документ «Алгоритм дерева потоковой параллельной принятия решений» и более длинную версию того же документа.

Денсон
источник
5

2018 Обновление!

Вы можете создать пространство вложения (плотный вектор) для ваших категориальных переменных. Многие из вас знакомы с word2vec и fastext, которые встраивают слова в значимое плотное векторное пространство. Та же идея здесь - ваши категориальные переменные будут отображаться в вектор с некоторым значением.

Из статьи Го / Берхан :

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

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

Лучшим примером может служить применение этой методики Pinterest для группировки связанных Пинов:

введите описание изображения здесь

Ребята из fastai внедрили категорические вложения и создали очень хороший пост в блоге с сопроводительной демонстрационной записной книжкой .

Дополнительные детали и объяснение

Нейронная сеть используется для создания вложений, т.е. присваивает вектор каждому категориальному значению. Если у вас есть векторы, вы можете использовать их в любой модели, которая принимает числовые значения. Каждый компонент вектора становится входной переменной. Например, если вы использовали трехмерные векторы для встраивания своего категориального списка цветов, вы можете получить что-то вроде: красный = (0, 1.5, -2.3), синий = (1, 1, 0) и т. Д. Вы бы использовали три входные переменные в вашем случайном лесу, соответствующие трем компонентам. Для красных вещей c1 = 0, c2 = 1.5 и c3 = -2.3. Для синих вещей c1 = 1, c2 = 1 и c3 = 0.

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

  1. Сопоставить цвета с векторами RGB.
  2. Отобразить местоположения по широте / долготе векторов.
  3. В политической модели США сопоставьте города с некоторыми векторными компонентами, представляющими выравнивание по левому / правому краю, налоговое бремя и т. Д.
Пит
источник
ОК, круто, но если я что-то пропустил, это для сетей, чтобы закончить. Как мы можем создать вложение и затем передать это вложение в Forrest? Я предполагаю, что вам нужно обучить целую сеть со всеми функциями, а затем взять первые несколько слоев и использовать их в качестве входной функции для вашего Forrest. Не ясно, как это будет сделано.
Кит
@ Нейронная сеть используется для создания вложений, т.е. присваивает вектор каждому категориальному значению. Если у вас есть векторы, вы можете использовать их в любой модели, которая принимает числовые значения. Каждый компонент вектора становится входной переменной. Например, если вы использовали трехмерные векторы для встраивания своего категориального списка цветов, вы можете получить что-то вроде: красный = (0, 1.5, -2.3), синий = (1, 1, 0)и т. Д. В вашем случайном лесу вы будете использовать три входные переменные, соответствующие этим трем компонентам. Для красных вещей c1 = 0, c2 = 1.5 и c3 = -2.3. Для синих вещей c1 = 1, c2 = 1 и c3 = 0.
Пит
Я полностью понимаю концепцию, поскольку она довольно проста. Я имею в виду, как это будет сделано в реализации? Демонстрационная записка fast.ai, на которую вы ссылаетесь, в конце немного похожа на RandomForestRegressor, но я не очень понимаю, как это добавляет вложения.
Кит
Я думаю, что это может быть хорошим примером кода в Keras github.com/entron/entity-embedding-rossmann
Keith
3

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

Пример:

import pandas as pd
d = {'one' : pd.Series([1., 2., 3.,4.], index=['a', 'b', 'c','d']),'two' :pd.Series(['Paul', 'John', 'Micheal','George'], index=['a', 'b', 'c', 'd'])}
df = pd.DataFrame(d)

df_with_dummies= pd.get_dummies(df,columns=["two"],drop_first=False)
df_with_dummies
ozn
источник
2

Превратите их в числа, например, для каждой уникальной страны, содержащей уникальный номер (например, 1,2,3 и ...)

Также вам не нужно использовать One-Hot Encoding (или фиктивные переменные) при работе со случайным лесом, потому что деревья не работают как другие алгоритмы (такие как линейная / логистическая регрессия) и не работают на расстоянии (они работа с поиском хорошего разделения для ваших функций) так что не нужно для One-Hot Encoding

Араш Джамшиди
источник
1
Это на самом деле зависит от конкретного алгоритма, который обучает дерево. В частности, Scikit НЕ поддерживает категориальные переменные.
chuse