えんじにあのじゆうちょう

勉強したことを中心にアウトプットしていきます。

コードで理解する回帰木

はじめに

回帰木って実は使ったことなくて、理屈は決定木と同じだと知っていてもまぁやってみないことには、と思ったのでやってみることにしました。

実装

どういうふうにやるか

木構造で分割するときは、分割後の情報利得が最大になるようにします。
情報利得は以下の式で表されます。

 I(S_{all}) - \frac{N_{left}}{N_{all}} * I(S_{left}) - \frac{N_{right}}{N_{all}} * I(S_{right})

ここで I(S)に何を使うかが問題なわけですが、回帰木の場合はMSE等、回帰のlossを設定すれば良いです。

では例えば S = (x, y) = (1,1), (2,2), (5,5)とあったときに、これを決定木に入れることを考えます。(予測対象はyです)

まずはこのまま予測することを考えると平均値を返すのが普通だと思えるので、予測値は \frac{1+2+5}{3} = 4とします。
MSEは \frac{1}{N}\sum (y-y_pred)^2ですので、このときのMSEは4.67となります。これがこのときの I(S_{all})となります。

そして次に左右分割するわけですが、分け方は今回の場合、1. (1,1) / (2,2), (5,5)と2. (1,1), (2,2) / (5,5)の2通りありますので、
それぞれについて I(S_{left}),  I(S_{right})を計算します。

すると1.のとき、 I(S_{left}) = 0, I(S_{right}) = 2.25なので、 4.67 - \frac{1}{3} * 0 - \frac{2}{3} * 2.25 = 3.17となります。
同様に2.のとき、 I(S_{left}) = 0.5, I(S_{right}) = 0なので、 4.67 - \frac{2}{3} * 0.5  - \frac{1}{3} * 0  = 4.34となり、2の分け方のほうが利得が大きくなるので、2の分割が選択されます。

今回はこれ以上分けても微妙な感じですが、データ数がもっと大きい場合はこれを逐次繰り返していって回帰木とするわけです。

コード

毎回コードもブログに書いていましたが、管理が二重になるので今回は試しにcolabのコードを張っておきます。
colab.research.google.com

考察

決定木、改めて見ると丁度いい分割点を探して分割しているということがよくわかります。
これはつまり、目的変数の値に対する順番に意味のある説明変数があればうまく分割できていい感じの木が構築できますが、逆に例えば適当にLabelEncodeしたとしてもあまりいい特徴量にならない可能性があることを指していると考えられます。

線形モデルなどと違い、スケールはあまり意識することはなさそうですが、順番を意識したデータを組み上げていく、ということが重要そうですね。

f:id:marufeuillex:20200506223856p:plain
また、これは今回の結果ですが、このように構造がパッと見でわかるようであれば線形モデルなどを利用したほうが簡単なように思います。
一方、当たり前ですがX, yの対応だけで予測できるデータなんてほとんどないわけで、そういう複雑性の高いデータに対しては回帰木がいけるんだろうなぁ、と思いました。