2013-11-20 3 views
11

Я пытаюсь использовать категориальную inpust в дереве регрессии (или Random Forest Regressor), но sklearn продолжает возвращать ошибки и запрашивать числовые входы.Деревья регрессии или регресстор случайного леса с категориальными входами

import sklearn as sk 
MODEL = sk.ensemble.RandomForestRegressor(n_estimators=100) 
MODEL.fit([('a',1,2),('b',2,3),('a',3,2),('b',1,3)], [1,2.5,3,4]) # does not work 
MODEL.fit([(1,1,2),(2,2,3),(1,3,2),(2,1,3)], [1,2.5,3,4]) #works 

MODEL = sk.tree.DecisionTreeRegressor() 
MODEL.fit([('a',1,2),('b',2,3),('a',3,2),('b',1,3)], [1,2.5,3,4]) # does not work 
MODEL.fit([(1,1,2),(2,2,3),(1,3,2),(2,1,3)], [1,2.5,3,4]) #works 

В моем понимании, категорные входы должны быть возможны в этих методах без какого-либо преобразования (например WOE замещения).

У кого-нибудь еще было это затруднение?

спасибо!

ответ

16

scikit-learn не имеет выделенного представления для категориальных переменных (ака факторов R), один из возможных решений заключается в кодировании строки как int с помощью LabelEncoder:

import numpy as np 
from sklearn.preprocessing import LabelEncoder 
from sklearn.ensemble import RandomForestRegressor 

X = np.asarray([('a',1,2),('b',2,3),('a',3,2),('c',1,3)]) 
y = np.asarray([1,2.5,3,4]) 

# transform 1st column to numbers 
X[:, 0] = LabelEncoder().fit_transform(X[:,0]) 

regressor = RandomForestRegressor(n_estimators=150, min_samples_split=2) 
regressor.fit(X, y) 
print(X) 
print(regressor.predict(X)) 

Выход:

[[ 0. 1. 2.] 
[ 1. 2. 3.] 
[ 0. 3. 2.] 
[ 2. 1. 3.]] 
[ 1.61333333 2.13666667 2.53333333 2.95333333] 

Но помните, что это небольшой взлом, если a и b являются независимыми категориями и он работает только с древовидными оценками. Зачем? Потому что b на самом деле не больше a. Правильный способ состоял бы в том, чтобы использовать OneHotEncoder после LabelEncoder или pd.get_dummies, давая две отдельные колонки с одним горячим кодированием для X[:, 0].

import numpy as np 
from sklearn.preprocessing import LabelEncoder, OneHotEncoder 
from sklearn.ensemble import RandomForestRegressor 

X = np.asarray([('a',1,2),('b',2,3),('a',3,2),('c',1,3)]) 
y = np.asarray([1,2.5,3,4]) 

# transform 1st column to numbers 
import pandas as pd 
X_0 = pd.get_dummies(X[:, 0]).values 
X = np.column_stack([X_0, X[:, 1:]]) 

regressor = RandomForestRegressor(n_estimators=150, min_samples_split=2) 
regressor.fit(X, y) 
print(X) 
print(regressor.predict(X)) 
+1

Спасибо за это. Я не думаю, что это решает проблему; «числовые метки» создают предположение о линейной прогрессии, которая, скорее всего, будет неверной по отношению к тому, что вы пытаетесь предсказать. Представьте себе узел дерева решений и при решении следующего разрыва отсечения, например, «<2 and > = 2» не имеет такого же смысла, как «если в (« a »,« c »)». – jpsfer

+0

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

+0

Большое спасибо Мэтту! – jpsfer

1

Необходимо ввести фиктивный код вручную в python. Я бы предложил использовать pandas.get_dummies() для одного горячего кодирования. Для Boosted деревьев у меня был успех, используя factorize() для достижения ординального кодирования.

Существует также целый пакет для такого рода вещей here.

Для более подробного объяснения смотрите в this Data Science Stack Обменный пост.

Смежные вопросы