Esse tópico refere-se a outros dois tópicos e a um bom artigo sobre esse assunto. Parece que ponderação de classe e downsampling são igualmente boas. Eu uso downsampling como descrito abaixo.
Lembre-se de que o conjunto de treinamento deve ser grande, pois apenas 1% caracterizará a classe rara. Menos de 25 a 50 amostras dessa classe provavelmente serão problemáticas. Poucas amostras que caracterizam a classe tornarão inevitavelmente o padrão aprendido e menos reprodutível.
O RF usa a votação majoritária como padrão. As prevalências de classe do conjunto de treinamento funcionarão como algum tipo de efetiva anterior. Assim, a menos que a classe rara seja perfeitamente separável, é improvável que essa classe rara ganhe uma votação majoritária ao prever. Em vez de agregar por maioria de votos, você pode agregar frações de votos.
A amostragem estratificada pode ser usada para aumentar a influência da classe rara. Isso é feito com o custo de reduzir a amostragem das outras classes. As árvores cultivadas se tornarão menos profundas, pois menos amostras precisam ser divididas, limitando a complexidade do padrão potencial aprendido. O número de árvores cultivadas deve ser grande, por exemplo, 4000, para que a maioria das observações participe de várias árvores.
No exemplo abaixo, simulei um conjunto de dados de treinamento de 5000 amostras com 3 classes com prevalências de 1%, 49% e 50%, respectivamente. Assim, haverá 50 amostras da classe 0. A primeira figura mostra a verdadeira classe de treinamento definida em função de duas variáveis x1 e x2.
Quatro modelos foram treinados: Um modelo padrão e três modelos estratificados com estratificação de classes 1:10:10 1: 2: 2 e 1: 1: 1. Principal enquanto o número de amostras inbag (incluindo redesenhos) em cada árvore será 5000, 1050, 250 e 150. Como não uso a votação por maioria, não preciso fazer uma estratificação perfeitamente equilibrada. Em vez disso, os votos em classes raras podem ser ponderados 10 vezes ou em alguma outra regra de decisão. Seu custo de falsos negativos e falsos positivos deve influenciar essa regra.
A próxima figura mostra como a estratificação influencia as frações de voto. Observe que as proporções estratificadas de classe sempre são o centróide das previsões.
Por fim, você pode usar uma curva ROC para encontrar uma regra de votação que ofereça uma boa relação entre especificidade e sensibilidade. A linha preta não possui estratificação, vermelha 1: 5: 5, verde 1: 2: 2 e azul 1: 1: 1. Para esse conjunto de dados 1: 2: 2 ou 1: 1: 1, parece a melhor opção.
A propósito, as frações de voto estão aqui com a validação cruzada.
E o código:
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)