Unterschied in der Implementierung von binären Teilungen in Entscheidungsbäumen


12

Ich bin gespannt auf die praktische Umsetzung einer binären Aufteilung in einem Entscheidungsbaum - bezogen auf Ebenen eines kategorialen Prädiktors .Xj

Insbesondere verwende ich beim Erstellen eines Vorhersagemodells unter Verwendung eines Entscheidungsbaums oft ein Stichprobenverfahren (z. B. Absacken, Überstichproben usw.), um die Genauigkeit und Stabilität der Vorhersage zu verbessern. Während dieser Abtastroutinen ist es möglich, dass eine kategoriale Variable einem Baumanpassungsalgorithmus mit weniger als der vollständigen eingestellten Ebene präsentiert wird.

Angenommen, eine Variable X nimmt Ebenen an {A,B,C,D,E}. In einer Stichprobe sind möglicherweise nur Ebenen {A,B,C,D}vorhanden. Wenn dann der resultierende Baum zur Vorhersage verwendet wird, kann der vollständige Satz vorhanden sein.

Wenn Sie mit diesem Beispiel fortfahren, sagen Sie, ein Baum teilt sich in X und sendet {A,B}nach links und {C,D}rechts. Ich würde erwarten, dass die Logik der binären Aufteilung dann sagt, wenn sie mit neuen Daten konfrontiert wird: "Wenn X den Wert A oder B hat, sende nach links, andernfalls sende diesen Fall nach rechts". In einigen Implementierungen scheint Folgendes zu passieren: "Wenn X den Wert A oder B hat, nach links senden, wenn X den Wert C oder D hat, nach rechts senden". Wenn dieser Fall den Wert E annimmt, bricht der Algorithmus zusammen.

Was ist der "richtige" Weg, um einen binären Split zu handhaben? Es scheint, dass die viel robustere Methode oft, aber nicht immer implementiert wird (siehe Rpart unten).

Hier einige Beispiele:

Rpart schlägt fehl, die anderen sind ok.

#test trees and missing values

summary(solder)
table(solder$PadType)

# create train and validation
set.seed(12345)
t_rows<-sample(1:nrow(solder),size=360, replace=FALSE)
train_solder<-solder[t_rows,]
val_solder<-solder[-t_rows,]

#look at PadType
table(train_solder$PadType)
table(val_solder$PadType)
#set a bunch to missing
levels(train_solder$PadType)[train_solder$PadType %in% c('L8','L9','W4','W9')] <- 'MISSING'


#Fit several trees, may have to play with the parameters to get them to split on the variable

####RPART
mod_rpart<-rpart(Solder~PadType,data=train_solder)
predict(mod_rpart,val_solder)
#Error in model.frame.default(Terms, newdata, na.action = na.action, xlev = attr(object,  : 
#factor 'PadType' has new level(s) D6, L6, L7, L8, L9, W4

####TREE
mod_tree<-tree(Solder~PadType,data=train_solder,split="gini")
predict(mod_tree,val_solder) #works fine

####ctree
mod_ctree<-ctree(Solder~PadType,data=train_solder,control = ctree_control(mincriterion = 0.05))
predict(mod_ctree,val_solder) #works fine

Antworten:


9

Tatsächlich gibt es zwei Arten von Faktoren - geordnet (wie Winzig <Klein <Mittel <Groß <Riesig) und ungeordnet (Gurke, Karotte, Fenchel, Aubergine).
First Class ist das Gleiche wie Continuous - es ist nur einfacher, alle Pivots zu überprüfen, es gibt auch kein Problem mit der Erweiterung der Levels-Liste.
Für die zweite Klasse müssen Sie eine Reihe von Elementen erstellen, die in einen Zweig geleitet werden und den Rest in den anderen Zweig überführen. In diesem Fall können Sie entweder:

  1. Fehler werfen
  2. Nehmen wir an, dass eine unsichtbare Klasse in Ihren Lieblingszweig gehört
  3. Behandle dies als NA und wähle einen Zweig auf weniger zufällige Weise aus.

12#Kategorien-1-1ichich

Ich würde sagen, die sinnvollste Idee ist, den Benutzer dazu zu bringen, die gesamte Menge von Faktoren zu definieren (zum Beispiel macht R dies organisch, wobei Ebenen durch Teilmengenoperationen erhalten bleiben) und Option 1 für nicht deklarierte Ebenen und Option 2 für deklarierte Ebenen zu verwenden . Option 3. kann sinnvoll sein, wenn Sie bereits über eine NA-Verarbeitungsinfrastruktur verfügen.

*) Es gibt auch eine Nebenstrategie für eine nicht triviale Umcodierung von Ebenen in Zahlen, wie zum Beispiel die Breiman-Codierung - dies führt jedoch zu noch mehr Problemen.


1
Wollen Sie damit sagen, dass ctree oder tree in meinem Beispiel diesen ungeordneten Faktor tatsächlich als geordneten Faktor behandelt und ihn somit in den Zweig "0" sendet?
B_Miner

@mbq können Sie bitte erklären, warum die Gesamtzahl der Möglichkeiten, wie Sie die Teilung durchführen können, 2 ^ (# Kategorien + 1) - 2 beträgt. Ich verstehe nicht ganz, warum der Teil "-2" ist.
Kasa

Hmm, es scheint, als hätte ich diese Formel durcheinander gebracht. es gibt wie 2 ^ n n-Bit-Wörter, aber wir zählen nicht beide Wörter a und ~ a, also 2 ^ (n-1), und wir mögen keine Splits, die überhaupt nicht verschüttet werden, also 2 ^ (n-1) -1 (mit anderen Worten, wir zählen von 1). n = 1 ist dann ein Sonderfall.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.