2013-11-20 4 views
11

Ho cercato di utilizzare un inpust categoriale in un albero di regressione (o Regressore foresta casuale) ma sklearn continua a restituire errori e richiede input numerici.Alberi di regressione o Regressore foresta casuale con input categoriali

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 

A mio avviso, gli input categoriali dovrebbero essere possibili in questi metodi senza alcuna conversione (ad esempio la sostituzione WOE).

Qualcun altro ha avuto questa difficoltà?

grazie!

risposta

16

scikit-learn non ha rappresentanza dedicato per variabili categoriali (aka fattori R), una soluzione possibile è quella di codificare i stringhe come int utilizzando 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)) 

uscita:

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

Ma ricordate che questo è un piccolo trucco se a e b sono categorie indipendenti e funziona solo con gli stimatori ad albero. Perché? Perché b non è molto più grande di a. Il modo corretto sarebbe utilizzare OneHotEncoder dopo che lo LabelEncoder o pd.get_dummies ha generato due colonne separate con una sola temperatura per 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

Grazie per quello. Non penso che risolva il problema; le 'etichette numeriche' creano un'ipotesi di una progressione lineare che molto probabilmente non è vera a ciò che stai cercando di prevedere. Immagina un nodo di un albero decisionale e quando decidi il prossimo split cut-off usando per esempio '<2 and > = 2' non ha lo stesso significato di "if in ('a', 'c')". – jpsfer

+0

Ho letto male la tua domanda. Ho appena visto che vuoi trattare tutto come categorico. Aggiornerò l'esempio di conseguenza ... – Matt

+0

Molte grazie Matt! – jpsfer

1

È necessario codice fittizio a mano in python. Vorrei suggerire l'utilizzo di pandas.get_dummies() per una codifica a caldo. Per gli alberi Boosted ho avuto successo usando factorize() per ottenere la codifica ordinale.

C'è anche un intero pacchetto per questo genere di cose here.

Per una spiegazione più dettagliata, consultare this Post di scambio di dati Science Stack.