決定木のバイナリ分割の実装の違い


12

カテゴリー予測変数レベルに関連するため、決定ツリーでのバイナリ分割の実用的な実装に興味があります。バツj

具体的には、意思決定ツリーを使用して予測モデルを構築するときに、予測精度と安定性を向上させるために、ある種のサンプリングスキーム(バギング、オーバーサンプリングなど)をよく利用します。これらのサンプリングルーチン中に、カテゴリ変数が完全なレベルセットよりも少ないツリーフィッティングアルゴリズムに提示される可能性があります。

変数Xがレベルを取るとしましょう{A,B,C,D,E}。サンプルでは、​​おそらくレベルのみ{A,B,C,D}が存在します。次に、結果のツリーを予測に使用すると、完全なセットが存在する場合があります。

この例を続けて、Xでツリーが分割さ{A,B}れ、左と{C,D}右に送信されるとします。バイナリ分割のロジックは、新しいデータに直面したときに「Xの値がAまたはBである場合は左に送信し、そうでない場合はこのケースを右に送信する」と言います。一部の実装で発生するように見えるのは、「Xの値がAまたはBの場合、左に送信し、Xの値がCまたはDの場合、右に送信する」です。このケースが値Eをとると、アルゴリズムは故障します。

バイナリ分割を処理する「正しい」方法は何ですか?はるかに堅牢な方法が頻繁に実装されているようですが、常にそうではありません(以下のRpartを参照)。

次に例を示します。

Rpartは失敗しますが、他は大丈夫です。

#test trees and missing values

summary(solder)
table(solder$PadType)

# create train and validation
set.seed(12345)
t_rows<-sample(1:nrow(solder),size=360, replace=FALSE)
train_solder<-solder[t_rows,]
val_solder<-solder[-t_rows,]

#look at PadType
table(train_solder$PadType)
table(val_solder$PadType)
#set a bunch to missing
levels(train_solder$PadType)[train_solder$PadType %in% c('L8','L9','W4','W9')] <- 'MISSING'


#Fit several trees, may have to play with the parameters to get them to split on the variable

####RPART
mod_rpart<-rpart(Solder~PadType,data=train_solder)
predict(mod_rpart,val_solder)
#Error in model.frame.default(Terms, newdata, na.action = na.action, xlev = attr(object,  : 
#factor 'PadType' has new level(s) D6, L6, L7, L8, L9, W4

####TREE
mod_tree<-tree(Solder~PadType,data=train_solder,split="gini")
predict(mod_tree,val_solder) #works fine

####ctree
mod_ctree<-ctree(Solder~PadType,data=train_solder,control = ctree_control(mincriterion = 0.05))
predict(mod_ctree,val_solder) #works fine

回答:


9

実際には、順序付けられた(小さな<小<中<大きな<巨大のような)と順序付けられていない(キュウリ、ニンジン、フェンネル、Au子)の2つのタイプの要因があります。
ファーストクラスは連続クラスと同じです。すべてのピボットをチェックする方が簡単で、レベルリストを拡張しても問題はありません。
2番目のクラスでは、1つのブランチに向けられる要素のセットを作成する必要があり、残りは他のブランチに残されます。この場合、次のいずれかが可能です。

  1. エラーを投げる
  2. 目に見えないクラスがお気に入りのブランチに入ると仮定する
  3. これをNAとして扱い、より少ないランダムな方法でブランチを選択します。

現在、順序付けられていない因子を直接扱うのは難しいため、多くのアルゴリズムが「チート」し、順序付けられていない因子を順序付けられたものとして主張しているため、この問題に触れることさえありません*。残りは、通常、整数int型マスク、すなわち最適化を使用してに及び治療因子レベルについての分岐選択として番目のビットを。(なぜ32レベルに頻繁に制限があるのか​​疑問に思ったことはありませんか?)この設定では、見えないレベルが静かに「0」ブランチに入るのはごく自然なことです。しかし、これはあまりに「正しい」とは思えません。なぜこれを行う必要があるのでしょうか。また、属性選択でエントロピーを活用するために必要なレベルの数はどうですか?12#categories11

最も賢明な考えは、ユーザーに要因の完全なセットを定義させ(たとえば、Rがサブセット操作を通じてレベルを維持してこれを有機的に行う)、宣言されていないレベルにはオプション1を、宣言されたレベルにはオプション2を使用することです。既にNA処理インフラストラクチャを持っている場合は、オプション3が理にかなっています。

*)たとえば、Breimanエンコーディングのように、レベルを数値に簡単に再コーディングするサイド戦略もありますが、さらに多くの問題が発生します。


1
私の例のctreeまたはtreeは、実際にこの順序付けられていない因子を順序付けられた因子として扱い、それを「0」ブランチに送信すると言っていますか?
B_Miner

@mbqでは、分割を実行できる方法の合計数が2 ^(#categories + 1)-2である理由を説明してください。「-2」の部分がなぜなのかよくわかりません。

うーん、私はこの式を台無しにしたようです。2 ^ n nビットの単語がありますが、単語aと〜aの両方をカウントしないので、2 ^(n-1)であり、まったくこぼれないスプリットは好きではないので、2 ^(n-1)-1(つまり、1から数えます)。n = 1は特別な場合です。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.