ランダムフォレストから知識を取得する


127

ランダムフォレストはブラックボックスと見なされますが、最近、ランダムフォレストからどのような知識が得られるのかと考えていましたか?

最も明白なことは、変数の重要性です。最も単純なバリアントでは、変数の出現回数を計算するだけでそれを行うことができます。
私が考えていた2番目のことは相互作用です。木の数が十分に大きければ、変数のペアの出現回数をテストできると思います(カイ二乗独立のようなもの)。3番目のことは、変数の非線形性です。私の最初のアイデアは、変数対スコアのチャートを見ることでしたが、それが意味をなすかどうかはまだわかりません。

追加された2012.01.2012
動機

この知識を使用して、ロジットモデルを改善したいと思います。見落とされた相互作用と非線形性を見つけることは可能だと思います(または少なくとも希望します)。


1
Rを使用すると、ランダムフォレストで測定される重要度の異なるドットチャートを作成できます。
ジョージドンタス

1
確率的勾配木ブースティングのための変数重要度の測定方法に関する関連スレッド
Antoine

これはおそらく遅すぎると思いますが、ロジットモデルを改善したいだけなら、なぜ投げ縄後ロジスティック回帰を使用しないのですか?選択後、選択した係数を使用して、ペナルティ/収縮なしでモデルを再適合させることができます。チューニング手順を少し微調整する必要がありますが、これは、希望することを正確に行うはるかに直接的なオプションです。
ilprincipe

回答:


122

ランダムフォレストはほとんどブラックボックスではありません。それらは非常に簡単に解釈できる決定木に基づいています。

#Setup a binary classification problem
require(randomForest)
data(iris)
set.seed(1)
dat <- iris
dat$Species <- factor(ifelse(dat$Species=='virginica','virginica','other'))
trainrows <- runif(nrow(dat)) > 0.3
train <- dat[trainrows,]
test <- dat[!trainrows,]

#Build a decision tree
require(rpart)
model.rpart <- rpart(Species~., train)

これにより、単純な決定ツリーが作成されます。

> model.rpart
n= 111 

node), split, n, loss, yval, (yprob)
      * denotes terminal node

1) root 111 35 other (0.68468468 0.31531532)  
  2) Petal.Length< 4.95 77  3 other (0.96103896 0.03896104) *
  3) Petal.Length>=4.95 34  2 virginica (0.05882353 0.94117647) *

Petal.Length <4.95の場合、このツリーは観測を「その他」に分類します。4.95を超える場合、観測は「virginica」として分類されます。ランダムフォレストは、そのような多くのツリーの単純なコレクションであり、各ツリーはデータのランダムサブセットでトレーニングされます。次に、各ツリーは各観測の最終分類に「投票」します。

model.rf <- randomForest(Species~., train, ntree=25, proximity=TRUE, importance=TRUE, nodesize=5)
> getTree(model.rf, k=1, labelVar=TRUE)
  left daughter right daughter    split var split point status prediction
1             2              3  Petal.Width        1.70      1       <NA>
2             4              5 Petal.Length        4.95      1       <NA>
3             6              7 Petal.Length        4.95      1       <NA>
4             0              0         <NA>        0.00     -1      other
5             0              0         <NA>        0.00     -1  virginica
6             0              0         <NA>        0.00     -1      other
7             0              0         <NA>        0.00     -1  virginica

rfから個々のツリーを引き出して、その構造を見ることもできます。形式はrpartモデルの場合と少し異なりますが、必要に応じて各ツリーを検査し、データのモデリング方法を確認できます。

さらに、データセット内の各変数の予測された応答と実際の応答を調べることができるため、真にブラックボックスとなるモデルはありません。これは、構築しているモデルの種類に関係なく、良いアイデアです。

library(ggplot2)
pSpecies <- predict(model.rf,test,'vote')[,2]
plotData <- lapply(names(test[,1:4]), function(x){
  out <- data.frame(
    var = x,
    type = c(rep('Actual',nrow(test)),rep('Predicted',nrow(test))),
    value = c(test[,x],test[,x]),
    species = c(as.numeric(test$Species)-1,pSpecies)
    )
  out$value <- out$value-min(out$value) #Normalize to [0,1]
  out$value <- out$value/max(out$value)
  out
})
plotData <- do.call(rbind,plotData)
qplot(value, species, data=plotData, facets = type ~ var, geom='smooth', span = 0.5)

プロット

変数(花びらと花びらの長さと幅)を0〜1の範囲に正規化しました。応答も0-1です。0はotherで、1はvirginicaです。ご覧のとおり、ランダムフォレストは、テストセットであっても優れたモデルです。

さらに、ランダムフォレストは変数の重要度のさまざまな測定値を計算します。これは非常に有益です。

> importance(model.rf, type=1)
             MeanDecreaseAccuracy
Sepal.Length           0.28567162
Sepal.Width           -0.08584199
Petal.Length           0.64705819
Petal.Width            0.58176828

この表は、各変数を削除するとモデルの精度がどれだけ低下するかを表しています。最後に、ランダムなフォレストモデルから作成できる他の多くのプロットがあり、ブラックボックスで何が起こっているかを確認できます。

plot(model.rf)
plot(margin(model.rf)) 
MDSplot(model.rf, iris$Species, k=5)
plot(outlier(model.rf), type="h", col=c("red", "green", "blue")[as.numeric(dat$Species)])

これらの各機能のヘルプファイルを表示して、表示される内容をよりよく理解できます。


6
答えをありがとう、多くの有用な情報がありますが、それは私が探していたものとはまったく異なります。この質問の背後にある動機をより明確にする必要があるかもしれません。ランダムフォレストを使用してロジットモデルを改善します。改善することにより、相互作用を追加したり、非線形変換を使用したりします。
トメックタルチンスキ

@TomekTarczynskiこれは興味深い問題であり、私が今扱っているものに似ています。「ロジットモデル」とは、ロジスティック回帰または類似の何かを意味すると思いますか?すべての変数ペア間の相互作用があるモデルから予測変数を選択するために、lassoロジスティック回帰(glmnet Rパッケージから)を使用しています。非線形の用語はまだ追加していませんが、原則としてそれも可能です。私が推測する唯一の問題は、試行する非線形項(多項式項、指数変換など)を決定することです。また、私は高次のインタラクションを取り上げていませんが、それも簡単です。
アンZ.

2
@Tomek、あなたはこの答えから何を得ていないのですか?RでrandomForestパッケージを使用している場合、Zachが説明するプロットは非常に便利です。具体的には、varImpPlotを使用してロジットモデルの機能を選択し、partialPlotを使用して変換のタイプを推定し、ロジットモデルの連続予測子を試すことができます。後者のプロットを使用して、予測子と応答の間に非線形関係が存在する場所を特定し、その変換を明示的に行うか、その変数にスプラインを使用できるようにすることをお勧めします。
B_Miner

2
@b_miner-単なる推測ですが、ロジスティック回帰はすでに線形関係をキャプチャしているため、tomekは変数間の非線形相互作用を見つける方法を尋ねているようです。
rm999

@ rm999ロジットモデルで非線形相互作用をどのように定義しますか?変換された変数間で作成された相互作用項?
B_Miner

52

しばらく前に、RFモデルを会社の一部の化学者に適合させる必要がありました。さまざまな視覚化手法を試すのにかなりの時間を費やしました。その過程で、偶然フォレストの視覚化のためにRパッケージ(forestFloor)に入れたいくつかの新しい手法を偶然思いつきました。

古典的なアプローチは、Rminer(データベースに基づいた感度分析が部分依存に再発明された)、またはrandomForestパッケージのpartialPlotでサポートされている部分依存プロットです。相互依存関係を発見するエレガントな方法として、部分依存パッケージiceBOXを見つけました。edarfパッケージを使用していませんが、RF専用の優れた視覚化がいくつかあるようです。ggRandomForestのパッケージには、便利な可視化の大規模なセットが含まれています。

現在、forestFloorはrandomForestオブジェクトをサポートしています(他のRF実装のサポートは進行中です)。また、トレーニング後のこれらのツリーはランダムフォレストツリーとあまり変わらないため、勾配ブーストツリーの特徴寄与を計算できます。そのため、forestFloorは将来XGBoostをサポートできるようになります。部分依存プロットは完全にモデル不変です。

すべてのパッケージには、特徴空間から対象空間までのモデルの幾何学的マッピング構造を視覚化する共通点があります。正弦曲線y = sin(x)は、xからyへのマッピングであり、2Dでプロットできます。RFマッピングを直接プロットするには、多くの場合、ディメンションが多すぎます。代わりに、マッピング構造全体を投影、スライス、または分解して、マッピング構造全体を2Dの周辺プロットのシーケンスにまとめることができます。RFモデルが主要な効果のみをキャプチャし、変数間の相互作用を持たない場合、従来の視覚化方法で十分です。次に、次のようにモデル構造を単純化できますy=F(X)f1(x1)+f2(x2)+...+fd(xd)。次に、各変数による各部分関数を正弦曲線のように視覚化できます。RFモデルがかなりの相互作用をキャプチャしている場合、問題が大きくなります。構造の3Dスライスは、2つのフィーチャと出力間の相互作用を視覚化できます。問題は、視覚化する機能の組み合わせを知ることです(iceBOXはこの問題に対処します)。また、他の潜在的な相互作用がまだ考慮されていないかどうかを判断するのは簡単ではありません。

、この論文は、私は非常に小さいRFモデルが捕獲した生化学、実際どのような関係を説明するためにforestFloorの非常に初期のバージョンを使用していました。また、このホワイトペーパーでは、特徴の寄与の視覚化、ランダムフォレストの森林床の視覚化について詳しく説明します。

forestFloorパッケージからシミュレートされた例を貼り付けました。シミュレートされた隠された関数 noise を明らかにする方法を示します。y=x12+sin(x2π)+2x3x4+

#1 - Regression example:
set.seed(1234)
library(forestFloor)
library(randomForest)

#simulate data y = x1^2+sin(x2*pi)+x3*x4 + noise
obs = 5000 #how many observations/samples
vars = 6   #how many variables/features
#create 6 normal distr. uncorr. variables
X = data.frame(replicate(vars,rnorm(obs)))
#create target by hidden function
Y = with(X, X1^2 + sin(X2*pi) + 2 * X3 * X4 + 0.5 * rnorm(obs)) 

#grow a forest
rfo = randomForest(
  X, #features, data.frame or matrix. Recommended to name columns.
  Y, #targets, vector of integers or floats
  keep.inbag = TRUE,  # mandatory,
  importance = TRUE,  # recommended, else ordering by giniImpurity (unstable)
  sampsize = 1500 ,   # optional, reduce tree sizes to compute faster
  ntree = if(interactive()) 500 else 50 #speedup CRAN testing
)

#compute forestFloor object, often only 5-10% time of growing forest
ff = forestFloor(
  rf.fit = rfo,       # mandatory
  X = X,              # mandatory
  calc_np = FALSE,    # TRUE or FALSE both works, makes no difference
  binary_reg = FALSE  # takes no effect here when rfo$type="regression"
)


#plot partial functions of most important variables first
plot(ff,                       # forestFloor object
     plot_seq = 1:6,           # optional sequence of features to plot
     orderByImportance=TRUE    # if TRUE index sequence by importance, else by X column  
)

ここに画像の説明を入力してください

#Non interacting features are well displayed, whereas X3 and X4 are not
#by applying color gradient, interactions reveal themself 
#also a k-nearest neighbor fit is applied to evaluate goodness-of-fit
Col=fcol(ff,3,orderByImportance=FALSE) #create color gradient see help(fcol)
plot(ff,col=Col,plot_GOF=TRUE) 

ここに画像の説明を入力してください

#feature contributions of X3 and X4 are well explained in the context of X3 and X4
# as GOF R^2>.8


show3d(ff,3:4,col=Col,plot_GOF=TRUE,orderByImportance=FALSE)

ここに画像の説明を入力してください ここに画像の説明を入力してください

最後に、J.Friedmanが記述したA.Liawがコーディングした部分依存プロットのコード。これは主な効果に対してはうまくいきます。

par(mfrow=c(2,3))
for(i in 1:6) partialPlot(rfo,X,x.var=names(X)[i])

ここに画像の説明を入力してください


先に、ブーストされたツリーの機能の寄与も計算できると仮定しました。テストアルゴリズムを作成しましたが、それは可能です。残念ながら、ブーストされたツリーの機能の寄与は、バギングされたツリーと同じ有益な特性を示しません。1つの機能の効果は、すべての機能の寄与に分散する傾向があるため、視覚化は非常に混乱します。
ソレンHavelundウェリング

おっと!テストアルゴリズムにバグが見つかり、すべての問題が消えてしまいました。forestFloorは、グラディエントブーストされたツリーで正常に機能するように更新できます。
ソレンHavelundウェリング

3
forestFloorはgbmオブジェクトを受け入れるように更新されていますか?
ミシャ

これまで、私はrandomForest実装を完全に機能する勾配ブースティングマシンにラップし、機能の寄与を計算するためのいくつかのメソッドを定義する、逆の実装を行ってきました。実装は実際には合理的に効率的だと思います。:あなたはここにコードを見つけることができますgithub.com/sorhawell/forestFloor/blob/master/inst/examples/...
ソレンHavelundウェリング

完全なポートを作成するのは大変な作業です:)この実装はかなりの数行で行われました。
ソレンHavelundウェリング

24

これらのすばらしい応答を補足するために、勾配ブーストされたツリーの使用について言及します(例:RのGBMパッケージ)。Rでは、代入が必要なrandomForestと比較して欠損値が許可されるため、これをランダムフォレストよりも優先します。変数の重要度と部分プロットは(randomForestのように)利用可能で、ロジットモデルでの特徴選択と非線形変換の探索に役立ちます。さらに、変数の相互作用は、FriedmanのH統計(interact.gbm)で参照されJ.H. Friedman and B.E. Popescu (2005). “Predictive Learning via Rule Ensembles.” Section 8.1ます。TreeNetと呼ばれる商用バージョンはSalford Systemsから入手できます。このビデオプレゼンテーションでは、変数の相互作用の推定に関するビデオについて説明しています。


2
私は同意します、GBMはランダムフォレストからの論理的な次のステップです。
ザック

@B_miner:すばらしい!方法はわかりませんが、GBMは見落としていました。GBMを使用すると、相互作用と非線形性を簡単に検出できます。
トメックタルチンスキ

15

遅い答えですがforestFloor、自動化された方法でこの「ブラックボックス化解除」タスクを実行するのに役立つ最近のRパッケージ(2015)に出会いました。とても有望に見えます!

library(forestFloor)
library(randomForest)
#simulate data
obs=1000
vars = 18
X = data.frame(replicate(vars,rnorm(obs)))
Y = with(X, X1^2 + sin(X2*pi) + 2 * X3 * X4 + 1 * rnorm(obs))
#grow a forest, remeber to include inbag
rfo=randomForest(X,Y,keep.inbag = TRUE,sampsize=250,ntree=50)
#compute topology
ff = forestFloor(rfo,X)
#ggPlotForestFloor(ff,1:9)
plot(ff,1:9,col=fcol(ff))

以下のプロットを作成します。

ここに画像の説明を入力してください

インタラクションを探している場合は、3次元の視覚化も提供します。


4
最後の行の代わりにggplot2のサポートを削除しました。例: plot(ff、1:9、col = fcol(ff、1:4))
Soren Havelund Welling

9

Zachが述べたように、モデルを理解する1つの方法は、予測子が変化するときに応答をプロットすることです。plotmo Rパッケージを使用すると、「任意の」モデルに対してこれを簡単に行うことができます。例えば

library(randomForest)
data <- iris
data$Species <- factor(ifelse(data$Species=='virginica','virginica','other'))
mod <- randomForest(Species~Sepal.Length+Sepal.Width, data=data)
library(plotmo)
plotmo(mod, type="prob")

与える

プロット

これにより、1つの変数が変更され、他の変数は中央値に保持されます。交互作用プロットの場合、2つの変数が変更されます。(2016年11月に追加された注:plotmo部分依存プロットもサポートするようになりました。)

上記の例では、2つの変数のみを使用しています。より複雑なモデルは、一度に1つまたは2つの変数を調べることにより、断片的に視覚化できます。「その他」の変数は中央値に保持されているため、これはデータのスライスのみを示していますが、依然として有用です。いくつかの例は、plotmoパッケージのビネットにあります。他の例は、rpart.plotパッケージを使用したrpartツリープロットの第10章にあります


4

私は自分でこの種の質問にとても興味があります。ランダムフォレストから取得できる情報はたくさんあると思います。

インタラクションについては、ブライマンとカルティエはすでに、特に分類RFについてそれを調べようとしたようです。

私の知る限り、これはrandomForest Rパッケージには実装されていません。たぶんそれはそれほど単純ではないかもしれないし、「変数相互作用」の意味があなたの問題に非常に依存しているからかもしれません。

非線形性については、何を探しているのかわかりません。回帰フォレストは、使用する非線形関数のタイプに関する事前条件なしに、非線形重回帰問題に使用されます。


3

ゲームの後半ではありますが、LIMESHAPなど、この点でいくつかの新しい開発があります。また、チェックする価値のあるパッケージはDALEXです(特にRを使用しているが、いずれにしても素晴らしいチートシートなどが含まれている場合)。これらはすべてモデルに依存しないため、ランダムフォレスト、GBM、ニューラルネットワークなどで機能します。


(+1)素晴らしいリソース!
mkt

2

データについてより多くの情報を提供するランダムフォレストのわずかな変更は、最近開発された因果性フォレストの方法です。参照してくださいGRF-Rのパッケージとやる気紙ここに。その考えは、ランダムフォレストベースライン手法を使用して、因果効果の不均一性を見つけることです。

以前の論文(ここ)は、単純な因果性のある森林への詳細なアプローチを示しています。論文の9ページには、原因ツリーを成長させるための段階的な手順が記載されており、通常の方法でそれをフォレストに拡張できます。Athey and Wager 2017の9ページから取られました

式4:

式4

式5: 式5


1
因果ツリーの手順を示すために、以前のペーパーへのリンクとそのペーパーのスクリーンショットで更新されました。
gannawag

1

ここでの私の質問に関連する最新の回答(シードを修正することでランダムフォレストを100%解釈可能にすることはできますか?):

してみましょう boostrappedトレーニングセットの作成時にシードこと、および 機能のサブセット(簡略化のために、私は唯一のリストここでは種子の2種類)の選択にシードこと。z 2z1z2

  1. から、ブースタートレーニングセットが作成されます:、、、...、。 m D 1z 1D 2z 1D 3z 1D mz 1z1mD1(z1)D2(z1)D3(z1)Dm(z1)
  2. これらのトレーニングセットから、mT1(z1,z2)T2(z1,z2)T3(z1,z2)Tm(z1,z2)
  3. jth(j=1,2,...,m)xif^j(xi)(in,jm)
    F^(xi)=>1mj=1mf^j(xi)
  4. F^(xi)(z1,z2)xi
  5. xi
    x1F^(x1) - which is fixed> thanks to (z1,z2)
    x2F^(x2) -> which is fixed thanks to (z1,z2)
    x3→>F^(x3) - which is fixed thanks to (z1,z2)
    x4>→F^(x4) - which is fixed thanks to (z1,>z2)
    ....
  6. x1x2

これは、ツリーの集約に基づくすべてのアンサンブルメソッドでも機能します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.