Ottenere conoscenza da una foresta casuale


127

Le foreste casuali sono considerate scatole nere, ma recentemente stavo pensando a quali conoscenze si possano ottenere da una foresta casuale?

La cosa più ovvia è l'importanza delle variabili, nella variante più semplice può essere fatto semplicemente calcolando il numero di occorrenze di una variabile.
La seconda cosa a cui stavo pensando sono le interazioni. Penso che se il numero di alberi è sufficientemente grande, allora il numero di occorrenze di coppie di variabili può essere testato (qualcosa come l'indipendenza del chi quadrato). La terza cosa sono le non linearità delle variabili. La mia prima idea era solo quella di guardare un grafico di un punteggio Vs variabile, ma non sono ancora sicuro che abbia un senso.

Aggiunto 23.01.2012
Motivazione

Voglio usare questa conoscenza per migliorare un modello logit. Penso (o almeno spero) che sia possibile trovare interazioni e non linearità che sono state trascurate.


1
Usando R puoi produrre un diagramma a punti di importanza variabile misurato da una foresta casuale.
George Dontas,

1
un thread correlato su come vengono calcolate le misure di importanza variabile per il potenziamento dell'albero gradiente stocastico
Antoine,

Capisco che probabilmente è troppo tardi, ma se vuoi solo migliorare un modello logit, perché non usi la regressione logistica post-lasso? Puoi semplicemente rimontare il modello usando i coefficienti selezionati dopo la selezione senza penalizzazione / restringimento. Dovrai modificare un po 'la procedura di ottimizzazione, ma questa è un'opzione molto più diretta che fa esattamente quello che vuoi.
ilprincipe,

Risposte:


122

Le foreste casuali non sono quasi una scatola nera. Si basano su alberi decisionali, che sono molto facili da interpretare:

#Setup a binary classification problem
require(randomForest)
data(iris)
set.seed(1)
dat <- iris
dat$Species <- factor(ifelse(dat$Species=='virginica','virginica','other'))
trainrows <- runif(nrow(dat)) > 0.3
train <- dat[trainrows,]
test <- dat[!trainrows,]

#Build a decision tree
require(rpart)
model.rpart <- rpart(Species~., train)

Ciò si traduce in un semplice albero decisionale:

> model.rpart
n= 111 

node), split, n, loss, yval, (yprob)
      * denotes terminal node

1) root 111 35 other (0.68468468 0.31531532)  
  2) Petal.Length< 4.95 77  3 other (0.96103896 0.03896104) *
  3) Petal.Length>=4.95 34  2 virginica (0.05882353 0.94117647) *

Se Petal.Length <4.95, questo albero classifica l'osservazione come "altro". Se è maggiore di 4,95, classifica l'osservazione come "virginica". Una foresta casuale è una raccolta semplice di molti di questi alberi, in cui ognuno è addestrato su un sottoinsieme casuale di dati. Ogni albero quindi "vota" sulla classificazione finale di ogni osservazione.

model.rf <- randomForest(Species~., train, ntree=25, proximity=TRUE, importance=TRUE, nodesize=5)
> getTree(model.rf, k=1, labelVar=TRUE)
  left daughter right daughter    split var split point status prediction
1             2              3  Petal.Width        1.70      1       <NA>
2             4              5 Petal.Length        4.95      1       <NA>
3             6              7 Petal.Length        4.95      1       <NA>
4             0              0         <NA>        0.00     -1      other
5             0              0         <NA>        0.00     -1  virginica
6             0              0         <NA>        0.00     -1      other
7             0              0         <NA>        0.00     -1  virginica

Puoi anche estrarre singoli alberi da RF e osservarne la struttura. Il formato è leggermente diverso rispetto ai rpartmodelli, ma è possibile ispezionare ogni albero se lo si desidera e vedere come modella i dati.

Inoltre, nessun modello è veramente una scatola nera, poiché è possibile esaminare le risposte previste rispetto alle risposte effettive per ogni variabile nel set di dati. Questa è una buona idea indipendentemente dal tipo di modello che stai costruendo:

library(ggplot2)
pSpecies <- predict(model.rf,test,'vote')[,2]
plotData <- lapply(names(test[,1:4]), function(x){
  out <- data.frame(
    var = x,
    type = c(rep('Actual',nrow(test)),rep('Predicted',nrow(test))),
    value = c(test[,x],test[,x]),
    species = c(as.numeric(test$Species)-1,pSpecies)
    )
  out$value <- out$value-min(out$value) #Normalize to [0,1]
  out$value <- out$value/max(out$value)
  out
})
plotData <- do.call(rbind,plotData)
qplot(value, species, data=plotData, facets = type ~ var, geom='smooth', span = 0.5)

tracciare

Ho normalizzato le variabili (lunghezza e larghezza del petalo e del petalo) in un intervallo 0-1. La risposta è anche 0-1, dove 0 è altro e 1 è virginica. Come puoi vedere, la foresta casuale è un buon modello, anche sul set di test.

Inoltre, una foresta casuale calcolerà varie misure di importanza variabile, che possono essere molto istruttive:

> importance(model.rf, type=1)
             MeanDecreaseAccuracy
Sepal.Length           0.28567162
Sepal.Width           -0.08584199
Petal.Length           0.64705819
Petal.Width            0.58176828

Questa tabella rappresenta la quantità di rimozione di ogni variabile che riduce la precisione del modello. Infine, ci sono molte altre trame che puoi creare da un modello di foresta casuale, per vedere cosa sta succedendo nella casella nera:

plot(model.rf)
plot(margin(model.rf)) 
MDSplot(model.rf, iris$Species, k=5)
plot(outlier(model.rf), type="h", col=c("red", "green", "blue")[as.numeric(dat$Species)])

È possibile visualizzare i file della guida per ciascuna di queste funzioni per avere un'idea migliore di ciò che visualizzano.


6
Grazie per la risposta, ci sono molte informazioni utili, ma non è esattamente quello che stavo cercando. Forse devo chiarire meglio la motivazione alla base di questa domanda. Voglio usare una foresta casuale per migliorare un modello logit, migliorando intendo aggiungere qualche interazione o usare una trasformazione non lineare.
Tomek Tarczynski,

@TomekTarczynski è un problema interessante e simile a quello che sto affrontando in questo momento. Presumo per "modello logit" intendi la regressione logistica o qualcosa di simile? Sto usando la regressione logistica lazo (dal pacchetto glmnet R) per selezionare i predittori da un modello con interazioni tra tutte le coppie di variabili. Non ho ancora aggiunto in termini non lineari, ma in linea di principio dovrebbe essere possibile anche questo. L'unico problema che immagino è decidere quali termini non lineari provare (termini polinomiali, trasformazioni esponenziali, ecc.). Inoltre, non sto raccogliendo interazioni di ordine superiore, ma è anche facile.
Anne Z.

2
@Tomek, cosa non ottieni da questa risposta? Se stai usando il pacchetto randomForest in R, i grafici descritti da Zach dovrebbero essere molto utili. In particolare, è possibile utilizzare varImpPlot per la selezione delle funzionalità nel modello logit e partialPlot per stimare il tipo di trasformazione per provare predittori continui nel modello logit. Vorrei suggerire che quest'ultimo grafico venga utilizzato per determinare dove esistono relazioni non lineari tra predittore e risposta e quindi consente di effettuare esplicitamente tale trasformazione o di utilizzare una spline su quella variabile.
B_Miner

2
@b_miner - solo un'ipotesi, ma sembra che Tomek stia chiedendo come trovare interazioni non lineari tra le variabili perché la regressione logistica cattura già le relazioni lineari.
rm999

@ rm999 Come si definisce un'interazione non lineare in un modello logit? Termini di interazione creati tra variabili trasformate?
B_Miner

52

Qualche tempo fa ho dovuto giustificare un modello RF adatto ad alcuni chimici della mia azienda. Ho trascorso parecchio tempo a provare diverse tecniche di visualizzazione. Durante il processo, ho anche accidentalmente escogitato alcune nuove tecniche che ho inserito in un pacchetto R ( forestFloor ) appositamente per visualizzazioni forestali casuali.

L'approccio classico sono i diagrammi di dipendenza parziale supportati da: Rminer (l'analisi della sensibilità basata sui dati è reinventata dipendenza parziale), o partialPlot nel pacchetto randomForest . Trovo il pacchetto di dipendenza parziale iceBOX come un modo elegante per scoprire le interazioni. Non ho usato il pacchetto edarf , ma sembra avere delle belle visualizzazioni dedicate alla RF. Il pacchetto ggRandomForest contiene anche un ampio set di visualizzazioni utili.

Attualmente forestFloor supporta oggetti randomForest (il supporto per altre implementazioni RF è in arrivo). Inoltre, è possibile calcolare i contributi delle caratteristiche per gli alberi con gradiente aumentato, poiché questi alberi dopo l'allenamento non sono molto diversi dagli alberi forestali casuali. Quindi forestFloor potrebbe supportare XGBoost in futuro. I grafici di dipendenza parziale sono completamente invarianti di modello.

Tutti i pacchetti hanno in comune la visualizzazione della struttura di mappatura geometrica di un modello dallo spazio delle caratteristiche allo spazio di destinazione. Una curva sinusoidale y = sin (x) sarebbe una mappatura da x a y e può essere tracciata in 2D. Tracciare direttamente una mappatura RF spesso richiederebbe troppe dimensioni. Invece, la struttura di mappatura complessiva può essere proiettata, suddivisa o decomposta, in modo tale che l'intera struttura di mappatura sia ridotta in una sequenza di grafici marginali 2D. Se il tuo modello RF ha acquisito solo effetti principali e nessuna interazione tra variabili, i metodi di visualizzazione classici andranno bene. Quindi puoi semplificare la struttura del tuo modello in questo modoy=F(X)f1(x1)+f2(x2)+...+fd(xd). Quindi ogni funzione parziale di ciascuna variabile può essere visualizzata proprio come la curva sinusoidale. Se il tuo modello RF ha acquisito interazioni considerevoli, allora è più problematico. Le sezioni 3D della struttura possono visualizzare le interazioni tra due funzioni e l'output. Il problema è sapere quale combinazione di funzionalità visualizzare ( iceBOX risolve questo problema). Inoltre, non è facile dire se altre interazioni latenti non sono ancora considerate.

In questo documento , ho usato una versione molto antica di forestFloor per spiegare quale reale relazione biochimica avesse catturato un modello RF molto piccolo. E in questo documento descriviamo a fondo le visualizzazioni dei contributi delle caratteristiche, le visualizzazioni di Forest Floor delle foreste casuali .

Ho incollato l'esempio simulato dal pacchetto forestFloor, dove mostro come scoprire una funzione nascosta simulata noisey=x12+sin(x2π)+2x3x4+

#1 - Regression example:
set.seed(1234)
library(forestFloor)
library(randomForest)

#simulate data y = x1^2+sin(x2*pi)+x3*x4 + noise
obs = 5000 #how many observations/samples
vars = 6   #how many variables/features
#create 6 normal distr. uncorr. variables
X = data.frame(replicate(vars,rnorm(obs)))
#create target by hidden function
Y = with(X, X1^2 + sin(X2*pi) + 2 * X3 * X4 + 0.5 * rnorm(obs)) 

#grow a forest
rfo = randomForest(
  X, #features, data.frame or matrix. Recommended to name columns.
  Y, #targets, vector of integers or floats
  keep.inbag = TRUE,  # mandatory,
  importance = TRUE,  # recommended, else ordering by giniImpurity (unstable)
  sampsize = 1500 ,   # optional, reduce tree sizes to compute faster
  ntree = if(interactive()) 500 else 50 #speedup CRAN testing
)

#compute forestFloor object, often only 5-10% time of growing forest
ff = forestFloor(
  rf.fit = rfo,       # mandatory
  X = X,              # mandatory
  calc_np = FALSE,    # TRUE or FALSE both works, makes no difference
  binary_reg = FALSE  # takes no effect here when rfo$type="regression"
)


#plot partial functions of most important variables first
plot(ff,                       # forestFloor object
     plot_seq = 1:6,           # optional sequence of features to plot
     orderByImportance=TRUE    # if TRUE index sequence by importance, else by X column  
)

inserisci qui la descrizione dell'immagine

#Non interacting features are well displayed, whereas X3 and X4 are not
#by applying color gradient, interactions reveal themself 
#also a k-nearest neighbor fit is applied to evaluate goodness-of-fit
Col=fcol(ff,3,orderByImportance=FALSE) #create color gradient see help(fcol)
plot(ff,col=Col,plot_GOF=TRUE) 

inserisci qui la descrizione dell'immagine

#feature contributions of X3 and X4 are well explained in the context of X3 and X4
# as GOF R^2>.8


show3d(ff,3:4,col=Col,plot_GOF=TRUE,orderByImportance=FALSE)

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

Infine il codice per i diagrammi di dipendenza parziale codificato da A.Liaw descritto da J.Friedman. Che vanno bene per gli effetti principali.

par(mfrow=c(2,3))
for(i in 1:6) partialPlot(rfo,X,x.var=names(X)[i])

inserisci qui la descrizione dell'immagine


Ho postulato in precedenza che i contributi delle caratteristiche potevano anche essere calcolati per alberi potenziati. Ho scritto un algoritmo di prova ed è possibile. Sfortunatamente, i contributi delle funzionalità per gli alberi potenziati non mostrano le stesse proprietà benefiche degli alberi insaccati. Gli effetti di una caratteristica tendono a diffondersi tra tutti i contributi delle caratteristiche, quindi la visualizzazione diventa piuttosto confusa.
Soren Havelund Welling,

Oups! Ho trovato un bug nel mio algoritmo di test che ha dissipato tutti i problemi. forestFloor potrebbe essere aggiornato per funzionare perfettamente con alberi a gradiente.
Soren Havelund Welling,

3
forestFloor è aggiornato per accettare oggetti gbm?
Misha,

Finora, ho fatto un'implementazione inversa, che avvolge l'implementazione randomForest in una macchina di potenziamento del gradiente completamente funzionale e definisce alcuni metodi per calcolare i contributi delle funzionalità. Penso che l'implementazione sia effettivamente ragionevole. Puoi trovare il codice qui: github.com/sorhawell/forestFloor/blob/master/inst/examples/…
Soren Havelund Welling

Fare una porta completa è un duro lavoro :) Questa implementazione è stata fatta in poche righe.
Soren Havelund Welling,

24

Per integrare queste belle risposte, vorrei citare l'uso di alberi con gradiente incrementato (ad es. Il pacchetto GBM in R ). In R, preferisco questo a foreste casuali perché sono consentiti valori mancanti rispetto a randomForest dove è richiesta l'imputazione. Importanza variabile e grafici parziali sono disponibili (come in randomForest) per facilitare la selezione delle caratteristiche e l'esplorazione della trasformazione non lineare nel modello logit. Inoltre, l'interazione variabile viene affrontata con la statistica H di Friedman ( interact.gbm) con riferimento dato come J.H. Friedman and B.E. Popescu (2005). “Predictive Learning via Rule Ensembles.” Section 8.1. Una versione commerciale chiamata TreeNet è disponibile da Salford Sistemi e questo video di presentazione parla a loro assumere variabile stima interazione video .


2
Sono d'accordo, i GBM sono un passo logico successivo da foreste casuali.
Zach,

@B_miner: fantastico! Non so come, ma ho trascurato GBM. Sembra che usando GBM sia facile rilevare interazioni e non linearità.
Tomek Tarczynski,

15

Risposta in ritardo, ma mi sono imbattuto in un recente pacchetto R forestFloor(2015) che ti aiuta a svolgere questo compito di "unblackboxing" in modo automatizzato. Sembra molto promettente!

library(forestFloor)
library(randomForest)
#simulate data
obs=1000
vars = 18
X = data.frame(replicate(vars,rnorm(obs)))
Y = with(X, X1^2 + sin(X2*pi) + 2 * X3 * X4 + 1 * rnorm(obs))
#grow a forest, remeber to include inbag
rfo=randomForest(X,Y,keep.inbag = TRUE,sampsize=250,ntree=50)
#compute topology
ff = forestFloor(rfo,X)
#ggPlotForestFloor(ff,1:9)
plot(ff,1:9,col=fcol(ff))

Produce i seguenti grafici:

inserisci qui la descrizione dell'immagine

Fornisce anche una visualizzazione tridimensionale se stai cercando interazioni.


4
Ho rimosso il supporto per ggplot2, invece dell'ultima riga provare ad esempio: plot (ff, 1: 9, col = fcol (ff, 1: 4))
Soren Havelund Welling

9

Come menzionato da Zach, un modo per comprendere un modello è quello di tracciare la risposta al variare dei predittori. Puoi farlo facilmente per "qualsiasi" modello con il pacchetto plotmo R. Per esempio

library(randomForest)
data <- iris
data$Species <- factor(ifelse(data$Species=='virginica','virginica','other'))
mod <- randomForest(Species~Sepal.Length+Sepal.Width, data=data)
library(plotmo)
plotmo(mod, type="prob")

che dà

tracciare

Questo cambia una variabile mantenendo le altre ai loro valori mediani. Per i grafici di interazione, cambia due variabili. (Nota aggiunta novembre 2016: plotmoora supporta anche i grafici di dipendenza parziale.)

L'esempio sopra usa solo due variabili; modelli più complicati possono essere visualizzati in modo frammentario osservando una o due variabili alla volta. Dato che le "altre" variabili sono mantenute ai loro valori mediani, questo mostra solo una porzione dei dati, ma può ancora essere utile. Alcuni esempi sono nella vignetta del pacchetto plotmo . Altri esempi sono nel capitolo 10 della stampa di alberi rpart con il pacchetto rpart.plot .


4

Sono molto interessato a questo tipo di domande da solo. Penso che ci siano molte informazioni che possiamo ottenere da una foresta casuale.

Per quanto riguarda le interazioni, sembra che Breiman e Cultier abbiano già provato a esaminarlo, in particolare per la classificazione delle RF.

Per quanto ne so, questo non è stato implementato nel pacchetto randomForest R. Forse perché potrebbe non essere così semplice e perché il significato di "interazioni variabili" dipende molto dal tuo problema.

Per quanto riguarda la non linearità, non sono sicuro di ciò che stai cercando, la foresta di regressione viene utilizzata per problemi di regressione multipla non lineare senza priori su quale tipo di funzione non lineare utilizzare.


3

Verso la fine del gioco, ma ci sono alcuni nuovi sviluppi in questo fronte, ad esempio LIME e SHAP . Anche un pacchetto che vale la pena controllare è DALEX (in particolare se si utilizza R ma in ogni caso contiene buoni cheatheet ecc.), Sebbene al momento non sembri coprire le interazioni. E questi sono tutti indipendenti dal modello, quindi funzioneranno per foreste casuali, GBM, reti neurali, ecc.


(+1) Belle risorse!
mkt

2

Una leggera modifica di foreste casuali che forniscono maggiori informazioni sui dati sono i metodi di foresta causale sviluppati di recente. Vedi il pacchetto R GRF e il documento motivante qui . L'idea è di utilizzare i metodi di base casuali della foresta per trovare l'eterogeneità negli effetti causali.

Un documento precedente ( qui ) fornisce un approccio dettagliato a una semplice foresta causale. La pagina 9 del documento fornisce una procedura passo-passo per la crescita di un albero causale, che può quindi essere espanso in una foresta come di consueto.Tratto da Pagina 9 di Athey and Wager 2017

Equazione 4:

Equazione 4

Equazione 5: Equazione 5


1
Aggiornato con collegamenti a precedenti documenti e schermate di tale documento per mostrare la procedura dell'albero causale.
Gannawag,

1

Risposta tardiva relativa alla mia domanda qui ( possiamo rendere Random Forest interpretabile al 100% fissando il seme? ):

Consenti a essere il seme nella creazione di un set di addestramento boostrapped e essere il seme nella selezione del sottoinsieme di funzionalità (per semplificazione, elencherò solo 2 tipi di semi qui).z1z2

  1. Da , vengono creati set di addestramento con boostrapped: , , , ..., . z1mD1(z1)D2(z1)D3(z1)Dm(z1)
  2. Da questi insiemi di traning, vengono creati alberi delle decisioni corrispondenti e ottimizzati tramite convalida incrociata: , , , ..., .mT1(z1,z2)T2(z1,z2)T3(z1,z2)Tm(z1,z2)
  3. Indichiamo le previsioni dall'albero per un singolo (dal set di addestramento o di prova, qualunque cosa) come . Quindi le previsioni finali degli alberi dell'insieme sono: jth(j=1,2,...,m)xif^j(xi)(in,jm)
    F^(xi)=>1mj=1mf^j(xi)
  4. Una volta che il modello è stato convalidato ed è stabile (che significa non dipende fortemente dalla coppia ). a creare tutte le possibili combinazioni delle mie funzionalità , che mi danno un set molto grande ( ).F^(xi)(z1,z2)xi
  5. L'applicazione della mia foresta su ogni mi dà le previsioni corrispondenti:xi
    x1F^(x1) - which is fixed> thanks to (z1,z2)
    x2F^(x2) -> which is fixed thanks to (z1,z2)
    x ' 4 > F (x ' 4 ) - che è fissata grazie a  ( z 1 , > z 2 ) . . . .
    x3→>F^(x3) - which is fixed thanks to (z1,z2)
    x4>→F^(x4) - which is fixed thanks to (z1,>z2)
    ....
  6. Quest'ultimo può essere facilmente rappresentato sotto forma di un singolo (enorme) albero . Ad esempio: : (Età = 18, sesso = M, ...), = (Età = 18, sesso = F, ...), ... potrebbero essere raggruppati per creare una foglia. x 2x1x2

Questo funziona anche per tutti i metodi di ensemble basati sull'aggregazione di alberi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.