K_DM Book
用語集
対象者 高校生
対象者別の入口 →

対象者の設定はこのブラウザの中にだけ保存されます。

言語 JA

決定木回帰(高校生向け)

入門高校生

02.3.2 高校生向け

決定木回帰(高校生向け)

最終更新 2026-11-01 読了時間 2 分
まとめ
決定木回帰は、データを「\(x\) は 25 以下?」のような質問で区間に切り分け、各区間に入った点の平均を予測値にする方法です。グラフにすると予測は階段状になり、質問を重ねる(木を深くする)ほど段が 2、4、8 と増えて曲線にも近づけます。切る場所は、左右の区間それぞれで「点と平均とのずれの 2 乗の合計」が最小になる場所で、数学Iの分散と同じ発想です。深くしすぎると段が細かくなりすぎて、学習データのノイズまで覚えてしまう過学習が起きます。

こんな場面を想像してみよう #

高校生向けの線形回帰 では、気温とアイスの売上の点に 1 本の直線を引きました。でも売店のおばさんの頭の中は、もしかすると直線ではなく「25 ℃ 以下なら 40 個くらい、25 ℃ を超えたら 75 個くらい」という、ざっくりした区切りかもしれません。

この「区間に分けて、区間ごとに代表の値を決める」考え方を、売上データから自動で作るのが決定木回帰です。分類の決定木と同じ「はい/いいえ」の質問を使いますが、最後に返すのがクラスではなく平均値、たとえば 40 個や 75 個になります。

回帰木の段差状予測。灰色の点がデータ、なめらかな線が本当の関係、階段状の線が深さ 3 の回帰木の予測。階段が曲線を追いかけている

上の図は、なめらかな曲線にノイズを加えたデータに、深さ 3 の回帰木を当てはめた結果です。予測(階段状の線)は 8 段の水平線でできていて、それぞれの段の高さが、その区間に入った点の平均です。

仕組み:いちばん「ばらつきが減る」場所で切る #

まず、全部の点を 1 つの区間に入れます。予測値は全体の平均で、図ではまだ水平線が 1 本だけです。次に、となり合う点の中間を 1 つずつ区切りにしてみて、左右それぞれの区間で「各点と区間の平均とのずれの 2 乗」を合計します。6 点なら候補は 5 か所です。その合計がいちばん小さくなる場所で切ると水平線が 2 段になり、左の段は左の点の平均、右の段は右の点の平均の高さになります。

できた区間それぞれで同じことを繰り返すと、段が 2、4、8 と増え、点の並びに沿った階段になっていきます。最後に、決めた深さ(max_depth)に達するか、区間の点が min_samples_leaf より少なくなったら止めます。新しい \(x\) が来たら、それが入る区間の平均を答えます。

決定木回帰の構造。各ノードに質問(x1 <= … など)、ずれの 2 乗の平均、サンプル数、その区間の平均値が書かれ、根から葉へ枝分かれしている

2 枚目の図は、特徴量が 2 つあるときの木を「質問の流れ」として描いたものです。葉に書かれた value が、その葉にたどりついた点に返す予測値(平均)です。特徴量が 2 つなら、区間は平面上の長方形の部屋になり、部屋ごとに 1 つの高さが決まります。

電卓感覚で計算してみる #

6 日分の気温と売上で、最初の 1 本をどこで切るかを総当たりで調べます。次のコードは、5 か所の候補すべてについて「左右のずれの 2 乗の合計」を計算し、cut at 25.0 C: error 528.0 の形で 1 行ずつ表示します。

1
2
3
4
5
6
7
8
9
temps = [22, 24, 26, 28, 30, 32]
sales = [38, 42, 60, 66, 82, 88]
def sse(ys):                                   # sum of squared deviations from mean
    m = sum(ys) / len(ys)
    return sum((y - m) ** 2 for y in ys)
for i in range(1, len(temps)):
    left, right = sales[:i], sales[i:]
    cut = (temps[i - 1] + temps[i]) / 2
    print(f"cut at {cut:4.1f} C: error {sse(left) + sse(right):7.1f}")

結果は 25 ℃ で切ったときが最小(528)で、27 ℃(533)がわずかに続きます。25 ℃ で切ると、左の区間の平均は 40 個、右は 74 個。「25 ℃ 以下なら 40 個、超えたら 74 個」という 2 段の階段が、最初の質問として選ばれます。

動かして見てみよう #

下の図で「再生」を押すと、説明した手順が 1 つずつ進みます。手順ごとの説明は図の下に出ます。

気をつけたいこと #

最初の注意点は、max_depth を深くしすぎると段が細かくなりすぎることです。点 1 つに 1 段ずつ作れば学習データにはぴったり合いますが、ノイズまで覚えた階段になり、新しいデータで外れます(情報IIの過学習)。max_depth や「葉に残す最小の点の数」min_samples_leaf で止めます。二つ目は、予測がガクガクすることで、区間の境目で値が 40 個から 74 個へ急に変わります。なめらかな予測が欲しいときは、木を 100 本平均するランダムフォレストなどを使います。三つ目は、学習した範囲の外は延長できないことで、気温が 22〜32 ℃ のデータで学んだ木に 40 ℃ を入れても、予測は「いちばん右の段の高さ」のままです。直線のように傾向を伸ばしてはくれません。

やってみよう #

最初の課題は、上のコードの sales を自分で決めた 6 個の数に書き換え、最初に切る場所がどこになるか予想してから実行することです。二つ目は、「直線より階段で表すほうが自然な関係」を身の回りから 2 つ探すことで、荷物の重さと送料、年齢と料金などが例です。三つ目は、点が 6 個しかないのに深さ 5 の木を作ったら階段が何段になるかを考え、新しい点に対して何が起きるかを max_depth の意味と結びつけて説明してみることです。

つぎに読む #

分割基準の式、2 特徴量の予測面、scikit-learn での実装は 標準版の決定木回帰 で扱っています。同じ木でクラスを当てる仕組みは 高校生向けの決定木分類、階段をなめらかにする方法は 高校生向けのランダムフォレスト へ進んでください。直線で予測する方法との比較は 高校生向けの線形回帰 を読み直してみてください。