Domanda in una frase: qualcuno sa come determinare pesi di buona classe per una foresta casuale?
Spiegazione: Sto giocando con set di dati non bilanciati. Voglio usare il Rpacchetto randomForestper formare un modello su un set di dati molto distorto con solo piccoli esempi positivi e molti esempi negativi. Lo so, ci sono altri metodi e alla fine li userò ma per motivi tecnici, la costruzione di una foresta casuale è un passaggio intermedio. Quindi ho giocato con il parametro classwt. Sto impostando un set di dati molto artificiale di 5000 esempi negativi nel disco con raggio 2 e quindi campiono 100 esempi positivi nel disco con raggio 1. Quello che sospetto è che
1) senza ponderazione di classe il modello diventa "degenerato", ovvero predice FALSEovunque.
2) con una ponderazione di classe discreta vedrò un 'punto verde' nel mezzo, cioè predirò il disco con raggio 1 come TRUEse ci fossero esempi negativi.
Ecco come appaiono i dati:
Questo è ciò che accade senza ponderazione: (chiamata è: randomForest(x = train[, .(x,y)],y = as.factor(train$z),ntree = 50))
Per verificare ho anche provato cosa succede quando bilanci violentemente il set di dati effettuando il downsampling della classe negativa in modo che la relazione sia di nuovo 1: 1. Questo mi dà il risultato atteso:
Tuttavia, quando calcolo un modello con una ponderazione di classe di 'FALSE' = 1, 'TRUE' = 50 (si tratta di una ponderazione corretta in quanto vi sono 50 volte più negativi che positivi) quindi ottengo questo:
Solo quando imposto i pesi su un valore strano come 'FALSO' = 0,05 e 'VERO' = 500000, ottengo risultati sensati:
E questo è abbastanza instabile, vale a dire cambiare il peso 'FALSO' a 0,01 fa degenerare di nuovo il modello (cioè predire TRUEovunque).
Domanda: qualcuno sa come determinare pesi di buona classe per una foresta casuale?
Codice R:
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")




