RandomForest- und Klassengewichte

11

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 RPaket randomForestverwenden, 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 TRUEob es negative Beispiele gäbe.

So sehen die Daten aus:

Geben Sie hier die Bildbeschreibung ein

Dies ist , was ohne Gewichtung geschieht: (Call ist: randomForest(x = train[, .(x,y)],y = as.factor(train$z),ntree = 50))

Geben Sie hier die Bildbeschreibung ein

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:

Geben Sie hier die Bildbeschreibung ein

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:

Geben Sie hier die Bildbeschreibung ein

Nur wenn ich die Gewichte auf einen seltsamen Wert wie 'FALSE' = 0,05 und 'TRUE' = 500000 setze, erhalte ich sinnvolle Ergebnisse:

Geben Sie hier die Bildbeschreibung ein

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")
Fabian Werner
quelle
Wenn Sampsize funktioniert, warum nicht? Ich fand auch, dass Sampsize besser funktioniert, um dieses Problem zu lösen, ebenso wie andere. Sehen Sie auch eine gute Antwort hier stats.stackexchange.com/questions/157714/…
katya
daply ist in plyr, das solltest du nennen.
EngrStudent
classwt Priors der Klassen. Muss nicht zu einem addieren. Für die Regression ignoriert.
Diego
@Diego: Dieser Parameter scheint sehr problematisch zu sein, ich verstehe nicht, wie sich dieser Parameter verhält (siehe die Kommentare in der Frage!) ...
Fabian Werner

Antworten:

2

Verwenden Sie keinen harten Cutoff, um eine harte Mitgliedschaft zu klassifizieren, und verwenden Sie keine KPIs, die von einer so harten Mitgliedschaftsvorhersage abhängen. Arbeiten Sie stattdessen mit einer probabilistischen Vorhersage, verwenden Sie predict(..., type="prob")diese und bewerten Sie sie anhand geeigneter .

Dieser frühere Thread sollte hilfreich sein: Warum ist Genauigkeit nicht das beste Maß für die Bewertung von Klassifizierungsmodellen? Es überrascht nicht, dass meine Antwort besonders hilfreich wäre (Entschuldigung für die Schamlosigkeit), ebenso wie eine frühere Antwort von mir .

Stephan Kolassa
quelle
1
Das ist das Thema, über das Sie heute gesprochen haben, oder?
Jonas Heidelberg