Передача категоріальних даних до Дерева рішень 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.