2016-02-07 9 views
9

sto usando uno scikit più alberi classificatore:Utilizzando scikit per determinare i contributi di ogni caratteristica per una specifica previsione di classe

model = ExtraTreesClassifier(n_estimators=10000, n_jobs=-1, random_state=0) 

volta che il modello è montato e utilizzato per prevedere le classi, mi piacerebbe scoprire la contributi di ciascuna caratteristica a una previsione di classe specifica. Come faccio a imparare questo in scikit? È possibile con un classificatore di alberi in più o devo usare qualche altro modello?

+0

Per curiosità, perché includi la libreria panda? – tmthydvnprt

risposta

6

Ho risolto un problema simile qualche tempo fa e ho pubblicato il same question on Cross Validated. La risposta breve è che non esiste un'implementazione in sklearn che fa tutto ciò che si desidera.

Tuttavia, ciò che si sta cercando di ottenere è davvero piuttosto semplice e può essere fatto moltiplicando il valore medio standardizzato medio di ciascuna divisione di funzione su ogni classe, con l'elemento di matrice model._feature_importances corrispondente. È possibile scrivere una semplice funzione che standardizza il set di dati, calcola la media di ogni suddivisione di funzionalità tra le previsioni di classe e fa moltiplicazioni a livello di elemento con l'array model._feature_importances. Più grandi sono i valori risultanti assoluti, più importanti saranno le caratteristiche della loro classe prevista e, meglio ancora, il segno indicherà se sono importanti valori piccoli o grandi.

Ecco un super semplice implementazioneche prende un DataMatrix X, un elenco di previsioni Y e una serie di funzionalità importances, ed emette un JSON descrive importanza di ogni caratteristica per ogni classe.

def class_feature_importance(X, Y, feature_importances): 
    N, M = X.shape 
    X = scale(X) 

    out = {} 
    for c in set(Y): 
     out[c] = dict(
      zip(range(N), np.mean(X[Y==c, :], axis=0)*feature_importances) 
     ) 

    return out 

Esempio:

import numpy as np 
import json 
from sklearn.preprocessing import scale 

X = np.array([[ 2, 2, 2, 0, 3, -1], 
       [ 2, 1, 2, -1, 2, 1], 
       [ 0, -3, 0, 1, -2, 0], 
       [-1, -1, 1, 1, -1, -1], 
       [-1, 0, 0, 2, -3, 1], 
       [ 2, 2, 2, 0, 3, 0]], dtype=float) 

Y = np.array([0, 0, 1, 1, 1, 0]) 
feature_importances = np.array([0.1, 0.2, 0.3, 0.2, 0.1, 0.1]) 
#feature_importances = model._feature_importances 

result = class_feature_importance(X, Y, feature_importances) 

print json.dumps(result,indent=4) 

{ 
    "0": { 
     "0": 0.097014250014533204, 
     "1": 0.16932975630904751, 
     "2": 0.27854300726557774, 
     "3": -0.17407765595569782, 
     "4": 0.0961523947640823, 
     "5": 0.0 
    }, 
    "1": { 
     "0": -0.097014250014533177, 
     "1": -0.16932975630904754, 
     "2": -0.27854300726557779, 
     "3": 0.17407765595569782, 
     "4": -0.0961523947640823, 
     "5": 0.0 
    } 
} 

Il primo livello di chiavi in ​​result sono etichette di classe, e il secondo livello di tasti da colonne indici, cioè dotate di indici. Ricorda che i valori assoluti di grandi dimensioni corrispondono all'importanza e il segno ti dice se sono piccoli (possibilmente negativi) o grandi valori importanti.

+0

grazie a @Ulf Aslak, puoi aggiungere un riferimento citabile? cioè un documento peer reviewed o qualcosa di simile? – user308827

+0

@ user308827 a mia conoscenza non ci sono riferimenti per citare questa piccola implementazione. Tuttavia, il codice non sta facendo nulla di particolare, utilizza solo le importanze delle funzionalità fornite dal modello e moltiplica quella con la media di ogni suddivisione di funzionalità in classe, perché possiamo presumere che per i dati normalizzati, le funzionalità ben separate disporranno di mezzi per ogni classe che sono molto lontani da 0. Ma c'è un sacco di lavoro che presenta metodi per la selezione di funzionalità specifiche di classe di varia complessità, perché dopotutto non è sempre così semplice. –

4

Questo viene modificato dalla docs

from sklearn import datasets 
from sklearn.ensemble import ExtraTreesClassifier 

iris = datasets.load_iris() #sample data 
X, y = iris.data, iris.target 

model = ExtraTreesClassifier(n_estimators=10000, n_jobs=-1, random_state=0) 
model.fit_transform(X,y) # fit the dataset to your model 

Credo feature_importances_ è quello che stai cercando:

In [13]: model.feature_importances_ 
Out[13]: array([ 0.09523045, 0.05767901, 0.40150422, 0.44558631]) 

EDIT

Forse ho capito male la prima volta (pre -bounty), mi dispiace, questo potrebbe essere più simile a quello che stai cercando. C'è una libreria python chiamata treeinterpreter che produce le informazioni che penso tu stia cercando. Dovrai utilizzare lo standard DecisionTreeClassifer (o Regressor). Proseguendo lungo da this blog post, è possibile accedere in modo discreto i contributi caratteristica nella previsione di ogni istanza:

from sklearn import datasets 
from sklearn.cross_validation import train_test_split 
from sklearn.tree import DecisionTreeClassifier 

from treeinterpreter import treeinterpreter as ti 

iris = datasets.load_iris() #sample data 
X, y = iris.data, iris.target 
#split into training and test 
X_train, X_test, y_train, y_test = train_test_split( 
    X, y, test_size=0.33, random_state=0) 

# fit the model on the training set 
model = DecisionTreeClassifier(random_state=0) 
model.fit(X_train,y_train) 

mi limiterò a scorrere ogni campione in X_test a scopo illustrativo, questa quasi esattamente imita il post di cui sopra:

for test_sample in range(len(X_test)): 
    prediction, bias, contributions = ti.predict(model, X_test[test_sample].reshape(1,4)) 
    print "Class Prediction", prediction 
    print "Bias (trainset prior)", bias 

    # now extract contributions for each instance 
    for c, feature in zip(contributions[0], iris.feature_names): 
     print feature, c 

    print '\n' 

La prima iterazione delle rese ciclo:

Class Prediction [[ 0. 0. 1.]] 
Bias (trainset prior) [[ 0.34 0.31 0.35]] 
sepal length (cm) [ 0. 0. 0.] 
sepal width (cm) [ 0. 0. 0.] 
petal length (cm) [ 0.   -0.43939394 0.43939394] 
petal width (cm) [-0.34  0.12939394 0.21060606] 

Interpretandola uscita, sembra come se la lunghezza del petalo e la larghezza del petalo fossero i contributi più importanti alla previsione della terza classe (per il primo campione). Spero che questo ti aiuti.

+1

grazie @Kevin, non credo che feature_importances_ mi dia quello che voglio. Ho appena trovato qualcosa che potrebbe: http://blog.datadive.net/interpreting-random-forests/ – user308827

+0

La mia modifica risponde più accuratamente alla tua domanda? – Kevin

+0

grazie a @Kevin, treeinterpretor non funziona con il classificatore ad albero extra di quello che sto utilizzando – user308827