Передача категоріальних даних до Дерева рішень Sklearn


78

Є кілька публікацій про те, як кодувати категоричні дані в дерева рішень Sklearn, але з документації Sklearn ми отримали

Деякі переваги дерев рішень:

(...)

Здатний обробляти як числові, так і категоріальні дані. Інші методи, як правило, спеціалізуються на аналізі наборів даних, які мають лише один тип змінних. Докладніше див. У алгоритмах.

Але запущений наступний скрипт

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['C'] = [0, 0, 1, 0]
data['Class'] = ['n','n','y','n']

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

виводить таку помилку:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/site-packages/sklearn/tree/tree.py", line 154, in fit
    X = check_array(X, dtype=DTYPE, accept_sparse="csc")
  File "/usr/local/lib/python2.7/site-packages/sklearn/utils/validation.py", line 377, in check_array
    array = np.array(array, dtype=dtype, order=order, copy=copy)
ValueError: could not convert string to float: b

Я знаю, що в R можна передавати категоричні дані за допомогою Sklearn, чи можливо це?

Відповіді:


-5

На відміну від прийнятої відповіді, я волів би використовувати для цього інструменти, надані Scikit-Learn. Основною причиною цього є те, що їх можна легко інтегрувати в трубопровід .

Сам Scikit-Learn пропонує дуже хороші класи для обробки категоріальних даних. Замість того , щоб писати для користувача функцію, ви повинні використовувати , LabelEncoderякий розроблений спеціально для цієї мети .

Зверніться до наступного коду з документації:

from sklearn import preprocessing
le = preprocessing.LabelEncoder()
le.fit(["paris", "paris", "tokyo", "amsterdam"])
le.transform(["tokyo", "tokyo", "paris"]) 

Це автоматично кодує їх у цифри для ваших алгоритмів машинного навчання. Тепер це також підтримує повернення до рядків із цілих чисел. Ви можете зробити це, просто зателефонувавши inverse_transformнаступним чином:

list(le.inverse_transform([2, 2, 1]))

Це повернеться ['tokyo', 'tokyo', 'paris'].

Також зауважте, що для багатьох інших класифікаторів, крім дерев рішень, таких як логістична регресія або SVM, ви хотіли б кодувати свої категоріальні змінні за допомогою кодування One-Hot . Scikit-learn також підтримує це через OneHotEncoderклас.

Сподіваюся, це допомагає!


152
-1 це вводить в оману. У своїй сутності дерева рішень sklearn не обробляють категоричні дані - див. Випуск № 5442 . Цей підхід використання кодування етикеток перетворює на цілі числа, які DecisionTreeClassifier() будуть розглядатися як числові . Якщо ваші категоричні дані не є порядковими, це погано - ви отримаєте розколи, які не мають сенсу. Використання a OneHotEncoder- єдиний дійсний на сьогоднішній день спосіб, але обчислювально дорогий.
James Owers

@Abhinav, чи можна застосувати LabelEncoderвідразу до кількох стовпців фрейму даних? Наприклад, у фреймі даних із запитання, чи можемо ми зробити щось на зразок le.fit_transform(data[['A','B','C']])отримання міток для всіх категоріальних стовпців одночасно? Або слід вказувати категоріальні стовпці явно для перетворення лише категоріальних стовпців.
Міну,

21
Це вводить в оману. Будь ласка, не перетворюйте рядки в числа та використовуйте їх у деревах рішень. Немає можливості обробляти категоричні дані в scikit-learn. Одним із варіантів є використання класифікатора дерева рішень у Spark - в якому ви можете чітко заявити про категоріальні ознаки та їх порядок. Детальніше див. Тут github.com/scikit-learn/scikit-learn/pull/4899
Прадіп Банавара

6
Кожен повинен вивчити шкали вимірювання, а саме номінальну, порядкову, інтервальну та співвідношення. Число не означає, що воно є числовим у номінальному масштабі; це просто прапор. Наприклад, ми можемо використовувати 1 для червоного, 2 для синього і 3 для зеленого. Скажімо, 10 осіб віддали перевагу червоному і 10 - зеленому. Чи є сенс розраховувати середнє значення ((10 * 1 + 10 * 3) / 20 = 2) і стверджувати, що в середньому перевага надається блакитному ??
Регі Метью

2
Е-е-е ... я навіть не підозрював, що у нього так багато уваги. Вітаємо @ayorgo, зроблю!
Джеймс

62

(Це лише переформатування мого вищезазначеного коментаря від 2016 року ... він все ще справедливий.)

Прийнята відповідь на це питання вводить в оману.

У своїй сутності дерева рішень sklearn не обробляють категоричні дані - див. Випуск № 5442 .

Рекомендований підхід використання кодування етикеток перетворює на цілі числа, які DecisionTreeClassifier()буде розглядатися як числові . Якщо ваші категоричні дані не є порядковими, це погано - ви отримаєте розколи, які не мають сенсу.

Використання a OneHotEncoder- це єдиний діючий поточний спосіб, який дозволяє довільні розбиття, що не залежать від упорядкування етикеток, але обчислювально дорого.


3
OneHotEncoding може погіршити продуктивність дерев рішень, мабуть, оскільки це призводить до надзвичайно розріджених функцій, які можуть зіпсувати значення функцій roamanalytics.com/2016/10/28/…
Арун

1
Погоджено - я не рекомендую такий підхід, але це єдиний спосіб уникнути проблеми, яку я описую зараз.
James Owers

Я підозрюю, що існують випадки (з функціями з багатьма малими рівнями), коли "нісенітниця" розділяється на звичайно закодовану категоріальну особливість, тим не менш, забезпечує кращу продуктивність, ніж дуже обмежені розбиття на функцію з одним гарячим кодуванням.
Бен Рейнігер

чи існує якась інша реалізація класифікатора дерева рішень, яка може це впоратись?
Модем Rakesh goud

12

(..)

Здатний обробляти як числові, так і категоріальні дані.

Це означає лише те, що ви можете використовувати

  • клас DecisionTreeClassifier для задач класифікації
  • клас DecisionTreeRegressor для регресії.

У будь-якому випадку вам потрібно одноразово кодувати категоріальні змінні, перш ніж розміщувати дерево за допомогою sklearn, приблизно так:

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['C'] = [0, 0, 1, 0]
data['Class'] = ['n','n','y','n']

tree = DecisionTreeClassifier()

one_hot_data = pd.get_dummies(data[['A','B','C']],drop_first=True)
tree.fit(one_hot_data, data['Class'])

2
Можливо, вам захочеться пограти з "pd.get_dummies", наприклад, параметр "drop_first = True" може допомогти уникнути проблем з мультиколінеарністю. Тут є гарний підручник.
Рафаель Валеро

4

Для номінальних категоріальних змінних, я б не використати , LabelEncoderале sklearn.preprocessing.OneHotEncoderі pandas.get_dummiesзамість цього , тому що звичайно не порядок цих типів змінних.


2

Дерева рішень Sklearn не обробляють перетворення категоріальних рядків у числа. Я пропоную вам знайти функцію в Sklearn (можливо, це ), яка робить це, або вручну напишіть такий код, як:

def cat2int(column):
    vals = list(set(column))
    for i, string in enumerate(column):
        column[i] = vals.index(string)
    return column

Так, це зазвичай роблять, але для друку це не дуже добре.
0xhfff

Якщо ви хочете повернутися від цілого числа до рядкового подання, створіть словник, який містить відображення між рядком і цілим числом, і використовуйте його для "декодування" цілочисельного подання.
mrwyatt

1
Твердження є неточним. Класифікатори Scikit-learn не неявно обробляють кодування міток. Однак Scikit-learn пропонує безліч класів для вирішення цього питання. Я б рекомендував використовувати інструменти для вивчення scikit, оскільки вони також можуть бути поміщені в трубопровід машинного навчання з мінімальними зусиллями.
Абхінав Арора
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.