Frage in einem Satz: Weiß jemand, wie man gute Klassengewichte für einen zufälligen Wald bestimmt?
Erläuterung: Ich spiele mit unausgeglichenen Datensätzen herum. Ich möchte das R
Paket randomForest
verwenden, um ein Modell auf einem sehr verzerrten Datensatz mit nur wenigen positiven und vielen negativen Beispielen zu trainieren. Ich weiß, es gibt andere Methoden, und am Ende werde ich sie anwenden, aber aus technischen Gründen ist das Erstellen eines zufälligen Waldes ein Zwischenschritt. Also habe ich mit dem Parameter herumgespielt classwt
. Ich richte einen sehr künstlichen Datensatz mit 5000 negativen Beispielen auf der Disc mit Radius 2 ein und probiere dann 100 positive Beispiele auf der Disc mit Radius 1 aus. Was ich vermute, ist das
1) Ohne Klassengewichtung wird das Modell "entartet", dh FALSE
überall vorhergesagt .
2) Bei einer angemessenen Klassengewichtung sehe ich einen "grünen Punkt" in der Mitte, dh es wird die Scheibe mit Radius 1 vorhergesagt, als TRUE
ob es negative Beispiele gäbe.
So sehen die Daten aus:
Dies ist , was ohne Gewichtung geschieht: (Call ist: randomForest(x = train[, .(x,y)],y = as.factor(train$z),ntree = 50)
)
Zur Überprüfung habe ich auch versucht, was passiert, wenn ich den Datensatz gewaltsam ausbalanciere, indem ich die negative Klasse heruntersetze, so dass die Beziehung wieder 1: 1 ist. Dies gibt mir das erwartete Ergebnis:
Wenn ich jedoch ein Modell mit einer Klassengewichtung von 'FALSE' = 1, 'TRUE' = 50 berechne (dies ist eine faire Gewichtung, da es 50-mal mehr Negative als Positive gibt), erhalte ich Folgendes:
Nur wenn ich die Gewichte auf einen seltsamen Wert wie 'FALSE' = 0,05 und 'TRUE' = 500000 setze, erhalte ich sinnvolle Ergebnisse:
Und dies ist ziemlich instabil, dh wenn das Gewicht 'FALSE' auf 0,01 geändert wird, degeneriert das Modell wieder (dh es wird TRUE
überall vorhergesagt ).
Frage: Weiß jemand, wie man gute Klassengewichte für einen zufälligen Wald bestimmt?
R-Code:
library(plot3D)
library(data.table)
library(randomForest)
set.seed(1234)
amountPos = 100
amountNeg = 5000
# positives
r = runif(amountPos, 0, 1)
phi = runif(amountPos, 0, 2*pi)
x = r*cos(phi)
y = r*sin(phi)
z = rep(T, length(x))
pos = data.table(x = x, y = y, z = z)
# negatives
r = runif(amountNeg, 0, 2)
phi = runif(amountNeg, 0, 2*pi)
x = r*cos(phi)
y = r*sin(phi)
z = rep(F, length(x))
neg = data.table(x = x, y = y, z = z)
train = rbind(pos, neg)
# draw train set, verify that everything looks ok
plot(train[z == F]$x, train[z == F]$y, col="red")
points(train[z == T]$x, train[z == T]$y, col="green")
# looks ok to me :-)
Color.interpolateColor = function(fromColor, toColor, amountColors = 50) {
from_rgb = col2rgb(fromColor)
to_rgb = col2rgb(toColor)
from_r = from_rgb[1,1]
from_g = from_rgb[2,1]
from_b = from_rgb[3,1]
to_r = to_rgb[1,1]
to_g = to_rgb[2,1]
to_b = to_rgb[3,1]
r = seq(from_r, to_r, length.out = amountColors)
g = seq(from_g, to_g, length.out = amountColors)
b = seq(from_b, to_b, length.out = amountColors)
return(rgb(r, g, b, maxColorValue = 255))
}
DataTable.crossJoin = function(X,Y) {
stopifnot(is.data.table(X),is.data.table(Y))
k = NULL
X = X[, c(k=1, .SD)]
setkey(X, k)
Y = Y[, c(k=1, .SD)]
setkey(Y, k)
res = Y[X, allow.cartesian=TRUE][, k := NULL]
X = X[, k := NULL]
Y = Y[, k := NULL]
return(res)
}
drawPredictionAreaSimple = function(model) {
widthOfSquares = 0.1
from = -2
to = 2
xTable = data.table(x = seq(from=from+widthOfSquares/2,to=to-widthOfSquares/2,by = widthOfSquares))
yTable = data.table(y = seq(from=from+widthOfSquares/2,to=to-widthOfSquares/2,by = widthOfSquares))
predictionTable = DataTable.crossJoin(xTable, yTable)
pred = predict(model, predictionTable)
res = rep(NA, length(pred))
res[pred == "FALSE"] = 0
res[pred == "TRUE"] = 1
pred = res
predictionTable = predictionTable[, PREDICTION := pred]
#predictionTable = predictionTable[y == -1 & x == -1, PREDICTION := 0.99]
col = Color.interpolateColor("red", "green")
input = matrix(c(predictionTable$x, predictionTable$y), nrow = 2, byrow = T)
m = daply(predictionTable, .(x, y), function(x) x$PREDICTION)
image2D(z = m, x = sort(unique(predictionTable$x)), y = sort(unique(predictionTable$y)), col = col, zlim = c(0,1))
}
rfModel = randomForest(x = train[, .(x,y)],y = as.factor(train$z),ntree = 50)
rfModelBalanced = randomForest(x = train[, .(x,y)],y = as.factor(train$z),ntree = 50, classwt = c("FALSE" = 1, "TRUE" = 50))
rfModelBalancedWeird = randomForest(x = train[, .(x,y)],y = as.factor(train$z),ntree = 50, classwt = c("FALSE" = 0.05, "TRUE" = 500000))
drawPredictionAreaSimple(rfModel)
title("unbalanced")
drawPredictionAreaSimple(rfModelBalanced)
title("balanced with weights")
pos = train[z == T]
neg = train[z == F]
neg = neg[sample.int(neg[, .N], size = 100, replace = FALSE)]
trainSampled = rbind(pos, neg)
rfModelBalancedSampling = randomForest(x = trainSampled[, .(x,y)],y = as.factor(trainSampled$z),ntree = 50)
drawPredictionAreaSimple(rfModelBalancedSampling)
title("balanced with sampling")
drawPredictionAreaSimple(rfModelBalancedWeird)
title("balanced with weird weights")