R-Paket für Weighted Random Forest? Klassewt Option?

16

Ich versuche, Random Forest zu verwenden, um das Ergebnis eines extrem unausgeglichenen Datensatzes vorherzusagen (die Minderheitsklassenrate beträgt nur etwa 1% oder sogar weniger). Da der herkömmliche Random Forest-Algorithmus die Gesamtfehlerrate minimiert, anstatt den Minderheitsklassen besondere Aufmerksamkeit zu widmen, ist er nicht direkt auf unausgeglichene Daten anwendbar. Daher möchte ich die Fehlklassifizierung der Minderheitenklasse (kostensensitives Lernen) mit hohen Kosten belasten.

Ich lese einige Quellen , dass wir die Möglichkeit nutzen können classwtvon randomForestin R, aber ich weiß nicht , wie diese zu verwenden. Und haben wir noch andere Alternativen zur randomForestFunktion?

Metariat
quelle

Antworten:

29

Dieser Thread bezieht sich auf zwei weitere Threads und einen guten Artikel zu diesem Thema. Es scheint, dass Klassengewichtung und Downsampling gleich gut sind. Ich benutze Downsampling wie unten beschrieben.

Denken Sie daran, dass der Trainingssatz groß sein muss, da nur 1% die seltene Klasse charakterisieren. Weniger als 25 bis 50 Proben dieser Klasse werden wahrscheinlich problematisch sein. Wenige Samples, die die Klasse charakterisieren, machen das erlernte Muster zwangsläufig grob und weniger reproduzierbar.

RF verwendet standardmäßig die Mehrheitsentscheidung. Die Klassenprävalenzen des Trainingssatzes gelten als eine Art wirksamer Prior. Daher ist es unwahrscheinlich, dass diese seltene Klasse bei der Vorhersage eine Mehrheit erhält, es sei denn, die seltene Klasse ist vollständig trennbar. Anstatt nach Stimmenmehrheit zu aggregieren, können Sie Stimmenbruchteile aggregieren.

Schichtproben können verwendet werden, um den Einfluss der seltenen Klasse zu erhöhen. Dies geschieht auf der Grundlage der Kosten für das Downsampling der anderen Klassen. Die gewachsenen Bäume werden weniger tief, da viel weniger Proben aufgeteilt werden müssen, wodurch die Komplexität des erlernten potenziellen Musters begrenzt wird. Die Anzahl der gewachsenen Bäume sollte groß sein, z. B. 4000, so dass die meisten Beobachtungen an mehreren Bäumen teilnehmen.

Im folgenden Beispiel habe ich einen Trainingsdatensatz von 5000 Proben mit 3 Klassen mit Prävalenzen von 1%, 49% bzw. 50% simuliert. Somit gibt es 50 Proben der Klasse 0. Die erste Abbildung zeigt die wahre Trainingsklasse als Funktion von zwei Variablen x1 und x2. Dieses Bild zeigt das zu lernende simulierte Muster

Es wurden vier Modelle trainiert: Ein Standardmodell und drei geschichtete Modelle mit einer 1: 2: 2- und einer 1: 1: 1-Klassenschichtung von 1:10:10. Main, während die Anzahl der Inbag-Samples (inkl. Neuzeichnungen) in jedem Baum 5000, 1050, 250 und 150 beträgt. Da ich keine Mehrheitsabstimmung verwende, muss ich keine perfekt ausgewogene Schichtung vornehmen. Stattdessen könnten die Stimmen in seltenen Klassen zehnmal oder nach einer anderen Entscheidungsregel gewichtet werden. Ihre Kosten für falsch negative und falsch positive Ergebnisse sollten diese Regel beeinflussen.

Die nächste Abbildung zeigt, wie die Schichtung die Stimmenanteile beeinflusst. Beachten Sie, dass die geschichteten Klassenverhältnisse immer der Schwerpunkt der Vorhersagen sind. Schichtung und Abstimmung

Zuletzt können Sie eine ROC-Kurve verwenden, um eine Abstimmungsregel zu finden, die Ihnen einen guten Kompromiss zwischen Spezifität und Sensitivität bietet. Schwarze Linie ist keine Schichtung, rot 1: 5: 5, grün 1: 2: 2 und blau 1: 1: 1. Für diesen Datensatz scheint 1: 2: 2 oder 1: 1: 1 die beste Wahl zu sein. ROC-Kurve

Stimmenbruchteile werden hier übrigens out-of-bag crossvalidiert.

Und der Code:

library(plotrix)
library(randomForest)
library(AUC)

make.data = function(obs=5000,vars=6,noise.factor = .2,smallGroupFraction=.01) {
X = data.frame(replicate(vars,rnorm(obs)))
yValue = with(X,sin(X1*pi)+sin(X2*pi*2)+rnorm(obs)*noise.factor)
yQuantile = quantile(yValue,c(smallGroupFraction,.5))
yClass = apply(sapply(yQuantile,function(x) x<yValue),1,sum)
yClass = factor(yClass)
print(table(yClass)) #five classes, first class has 1% prevalence only
Data=data.frame(X=X,y=yClass)
}

plot.separation = function(rf,...) {
triax.plot(rf$votes,...,col.symbols = c("#FF0000FF",
                                       "#00FF0010",
                                       "#0000FF10")[as.numeric(rf$y)])
}

#make data set where class "0"(red circles) are rare observations
#Class 0 is somewhat separateble from class "1" and fully separateble from class "2"
Data = make.data()
par(mfrow=c(1,1))
plot(Data[,1:2],main="separation problem: identify rare red circles",
     col = c("#FF0000FF","#00FF0020","#0000FF20")[as.numeric(Data$y)])

#train default RF and with 10x 30x and 100x upsumpling by stratification
rf1 = randomForest(y~.,Data,ntree=500, sampsize=5000)
rf2 = randomForest(y~.,Data,ntree=4000,sampsize=c(50,500,500),strata=Data$y)
rf3 = randomForest(y~.,Data,ntree=4000,sampsize=c(50,100,100),strata=Data$y)
rf4 = randomForest(y~.,Data,ntree=4000,sampsize=c(50,50,50)  ,strata=Data$y)

#plot out-of-bag pluralistic predictions(vote fractions).
par(mfrow=c(2,2),mar=c(4,4,3,3))
plot.separation(rf1,main="no stratification")
plot.separation(rf2,main="1:10:10")
plot.separation(rf3,main="1:5:5")
plot.separation(rf4,main="1:1:1")

par(mfrow=c(1,1))
plot(roc(rf1$votes[,1],factor(1 * (rf1$y==0))),main="ROC curves for four models predicting class 0")
plot(roc(rf2$votes[,1],factor(1 * (rf1$y==0))),col=2,add=T)
plot(roc(rf3$votes[,1],factor(1 * (rf1$y==0))),col=3,add=T)
plot(roc(rf4$votes[,1],factor(1 * (rf1$y==0))),col=4,add=T)
Soren Havelund Welling
quelle
Eine Zahl Bildunterschrift sagt 1: 5: 5 statt 1: 2: 2
Soren Havelund Welling
Vielen Dank für Ihre ausführliche Antwort, die mir bei meiner täglichen Arbeit auf jeden Fall sehr helfen wird. Es gibt einen Satz, den ich nicht verstehe: "Main, während die Anzahl der Inbag-Proben (inkl. Neuzeichnungen) in jedem Baum 5.000.1050, 250 und 150 beträgt." Können Sie mir bitte erklären, woher die Zahlen kommen?
Metariat
1
es war mir ein Vergnügen;) in diesem Beispiel hatte die seltene Klasse 50 Mitglieder. Bei einer Schichtung von 1:10:10 müssten wir sampsize = c (50,500,500) angeben. 50 + 500 + 500 = 1050. Ein ausgewachsener Baum mit 1050 Stichproben hat insgesamt 1050x2 Knoten.
Soren Havelund Welling
Entschuldigung, wenn meine Frage idiotisch ist, aber was bedeuten 1:10:10, 1: 2: 2 und 1: 1: 1 Schichtungen hier? Und als Sie sagten, "die Stimmen in seltenen Klassen könnten zehnmal gewichtet werden". Welcher Teil des Codes repräsentiert das? Ist es 1:10:10? Vielen Dank!
Metariat
1
1:10:10 sind die Verhältnisse zwischen den Klassen. Der simulierte Datensatz wurde mit einem Verhältnis von 1:49:50 erstellt. Diese Verhältnisse wurden durch Heruntertasten der beiden größeren Klassen geändert. Indem Sie z. B. sampsize = c (50.500.500) wie c (1.10.10) * 50 wählen, ändern Sie die Klassenverhältnisse in den Bäumen. 50 ist die Anzahl der Proben der seltenen Klasse. Wenn Sie außerdem keep.inbag = TRUE setzen und rf $ inbag prüfen, werden Sie feststellen, dass sich Proben der seltenen Klassen in ~ 2/3 Bäumen befinden, wohingegen jede nicht seltene Klassenprobe aufgrund von Daunenproben in sehr wenigen Bäumen enthalten ist.
Soren Havelund Welling