このスレッドは、他の2つのスレッドと、この問題に関するすばらしい記事を指します。クラスウェイトとダウンサンプリングも同様に良いようです。以下で説明するように、ダウンサンプリングを使用します。
まれなクラスを特徴付けるのは1%だけなので、トレーニングセットは大きくする必要があります。このクラスのサンプルは25〜50未満である可能性があります。クラスを特徴付けるサンプルはほとんどなく、必然的に学習パターンを粗雑にし、再現性を低下させます。
RFは多数決をデフォルトとして使用します。トレーニングセットのクラスの有病率は、何らかの効果的な事前分布として機能します。したがって、まれなクラスが完全に分離可能でない限り、このまれなクラスが予測時に多数決で勝つことはまずありません。多数決で集計する代わりに、投票の端数を集計できます。
層別サンプリングを使用して、まれなクラスの影響を増やすことができます。これは、他のクラスのダウンサンプリングのコストで行われます。分割する必要があるサンプルの数が少なくなると、成長したツリーの深さが浅くなり、学習される潜在的なパターンの複雑さが制限されます。ほとんどの観察結果が複数の木に参加するように、成長する木の数は、たとえば4000でなければなりません。
以下の例では、それぞれ1%、49%、50%の罹患率を持つ3つのクラスを持つ5000サンプルのトレーニングデータセットをシミュレートしました。したがって、クラス0の50個のサンプルがあります。最初の図は、2つの変数x1およびx2の関数としてのトレーニングセットの真のクラスを示しています。
4つのモデルがトレーニングされました:デフォルトモデル、およびクラスの1:10:10 1:2:2および1:1:1の階層化を持つ3つの階層化モデル。主に、各ツリーのインバッグサンプル(再描画を含む)の数は5000、1050、250、および150になります。多数決を使用しないため、完全にバランスのとれた層別化を行う必要はありません。代わりに、まれなクラスの投票に10倍の重みを付けるか、他の決定規則を使用できます。偽陰性と偽陽性のコストは、このルールに影響するはずです。
次の図は、層別化が投票率にどのように影響するかを示しています。階層化されたクラス比は常に予測の重心であることに注意してください。
最後に、ROC曲線を使用して、特異性と感度の間の適切なトレードオフを提供する投票ルールを見つけることができます。黒い線は層別化されていません、赤1:5:5、緑1:2:2、青1:1:1。このデータセットでは、1:2:2または1:1:1が最適です。
ちなみに、投票の端数はここですぐにクロス検証されます。
そしてコード:
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)