0Pricing
R Academy · レッスン

決定木:アンサンブルの基礎

rpart で決定木を構築・可視化し、バイアスと分散のトレードオフを理解します。

「決定木:アンサンブルの基礎」はCoddyKit上の無料R Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはR Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 R Academyコースには全4レッスンが含まれています。

決定木の分割方法

決定木は、特徴量空間を長方形の領域に再帰的に分割します。各ノードで、アルゴリズムはすべての特徴量と可能な分割点を調べ、目的変数を最も適切に分離できる分割を探します。その結果、if-elseルールで構成された木が得られます。

library(rpart)

# Fit a classification tree
tree <- rpart(
  Species ~ .,
  data   = iris,
  method = 'class'  # use 'anova' for regression
)

print(tree)

GINIとエントロピーの分割基準

分割基準は、ノードの不純度を測定します。Gini不純度は、ランダムに選んだ要素を誤分類する確率を測定します。エントロピー(情報利得)は、情報の無秩序さがどの程度減少したかを測定します。通常、どちらを使っても似た木になりますが、Giniのほうが計算が速く、rpartのデフォルトです。

# Default: Gini impurity (parms = list(split = 'gini'))
tree_gini <- rpart(Species ~ ., data = iris, method = 'class')

# Using information gain (entropy)
tree_entropy <- rpart(
  Species ~ ., data = iris, method = 'class',
  parms = list(split = 'information')
)

cat('Gini root split:', tree_gini$frame$var[1])
cat('Entropy root split:', tree_entropy$frame$var[1])

printcp() — 複雑度表

printcp(tree)は、複雑度パラメータ(CP)表を出力します。各行には、木のサイズ(分割数)、学習データに対する相対誤差、交差検証誤差(xerror)が示されます。CP表は、最適な枝刈りレベルを見つけるために使用します。

tree <- rpart(medv ~ ., data = MASS::Boston, method = 'anova',
              control = rpart.control(minsplit = 5, cp = 0.001))

printcp(tree)

# Identify the CP with minimum cross-validated error
best_cp <- tree$cptable[
  which.min(tree$cptable[, 'xerror']),
  'CP'
]
cat('Best CP:', best_cp)

prune() — 木を刈り込む

prune(tree, cp)は、cpで指定した複雑度レベルまで木を枝刈りします。枝刈りによって、予測への寄与が小さい分岐をまとめ、過学習を防ぎます。標準的な手順は、CV誤差を最小化するCPを見つけてから枝刈りすることです。

best_cp <- tree$cptable[
  which.min(tree$cptable[, 'xerror']), 'CP'
]

pruned_tree <- prune(tree, cp = best_cp)

cat('Original tree nodes:', nrow(tree$frame))
cat('Pruned tree nodes:', nrow(pruned_tree$frame))

rpart.plot() — 木を可視化する

rpart.plotパッケージのrpart.plot(tree)は、決定木を見やすく色付きで可視化します。各内部ノードには分割ルールが、各葉には予測クラスと学習サンプルの割合が表示されます。

library(rpart.plot)

tree <- rpart(Species ~ ., data = iris, method = 'class')
pruned <- prune(tree, cp = 0.02)

rpart.plot(
  pruned,
  type   = 4,     # split labels on branches
  extra  = 104,   # show class + probability
  fallen.leaves = TRUE
)

バイアスと分散のトレードオフ

深く枝刈りしていない木はバイアスが小さい(学習データにほぼ完全に適合する)一方で、分散が大きい(データが少し変わるだけで木が大きく変わる)という特徴があります。浅い木や枝刈りした木はバイアスが大きくなりますが、分散は小さくなります。最適な木は、この2つの誤差要因のバランスを取ります。

ランダムフォレストやブースティングなどのアンサンブル手法は、このトレードオフに直接対処します。

# Deep tree = low bias, high variance (overfits)
deep_tree <- rpart(medv ~ ., data = MASS::Boston,
                   control = rpart.control(minsplit = 2, cp = 0))

# Shallow tree = high bias, low variance (underfits)
shallow_tree <- rpart(medv ~ ., data = MASS::Boston,
                      control = rpart.control(maxdepth = 2))

cat('Deep nodes:', nrow(deep_tree$frame))
cat('Shallow nodes:', nrow(shallow_tree$frame))

決定木の過学習

枝刈りしていない木は、学習例をすべて記憶することで、学習誤差をゼロにできる場合があります。同じ木を未知のデータで評価すると、性能が急激に低下します。これは、教師あり学習における過学習の典型例です。

set.seed(42)
train_idx <- sample(nrow(MASS::Boston), 400)
train_bos <- MASS::Boston[train_idx, ]
test_bos  <- MASS::Boston[-train_idx, ]

# Fully grown tree
full <- rpart(medv ~ ., data = train_bos,
              control = rpart.control(cp = 0, minsplit = 2))

train_pred <- predict(full, train_bos)
test_pred  <- predict(full, test_bos)

cat('Train RMSE:', sqrt(mean((train_pred - train_bos$medv)^2)))
cat('Test  RMSE:', sqrt(mean((test_pred  - test_bos$medv)^2)))

rpartによる変数重要度

rpartは各予測変数についてvariable.importanceを記録します。これは、すべての分割において、その変数によってもたらされた分割基準の改善量を合計したものです。モデルの判断に大きく影響する特徴量を簡単に把握できます。

tree <- rpart(medv ~ ., data = MASS::Boston, method = 'anova')

# Variable importance (sorted)
imp <- sort(tree$variable.importance, decreasing = TRUE)
print(imp)

# Quick barplot
barplot(imp, las = 2, main = 'Variable Importance',
        col = 'steelblue', cex.names = 0.8)

木からアンサンブルへ

単一の決定木は不安定です。データを再サンプリングすると、まったく異なる木が生成されることがあります。アンサンブル手法は、この不安定性を利用します。

  • バギング/ランダムフォレスト:ブートストラップ標本で多数の木を作り、その予測を平均します。
  • ブースティング:木を順番に構築し、それぞれが前の木の誤りを修正します。
  • どちらも、木の表現力を維持しながら分散を小さくします。
# Demonstrating instability of a single tree
set.seed(1); t1 <- rpart(medv ~ ., data = MASS::Boston[sample(506, 400), ])
set.seed(2); t2 <- rpart(medv ~ ., data = MASS::Boston[sample(506, 400), ])

# Root split may differ between trees
cat('Tree 1 root split:', t1$frame$var[1])
cat('Tree 2 root split:', t2$frame$var[1])

rpartの制御パラメータ

rpart.control()は、木の成長方法を制御します。主なパラメータは、cp(複雑度ペナルティ)、minsplit(分割を試みるために必要な最小観測数)、minbucket(葉の最小サイズ)、maxdepthです。これらを理解することは、木ベースモデルのチューニングに不可欠です。

ctrl <- rpart.control(
  cp        = 0.005,  # complexity penalty
  minsplit  = 20,     # min obs to try a split
  minbucket = 7,      # min obs in any leaf
  maxdepth  = 10      # max tree depth
)

tree <- rpart(medv ~ ., data = MASS::Boston,
              method = 'anova', control = ctrl)

printcp(tree)

木の性能を評価する

枝刈りした後、ホールドアウトしたテストセットで木を評価します。回帰ではRMSEとR二乗を、分類では正解率と混同行列を計算します。これらの指標をベンチマークモデルと比較し、単一の木がもたらす価値を把握します。

pruned_tree <- prune(tree, cp = best_cp)

test_pred <- predict(pruned_tree, newdata = test_bos)

rmse <- sqrt(mean((test_pred - test_bos$medv)^2))
ss_res <- sum((test_pred - test_bos$medv)^2)
ss_tot <- sum((test_bos$medv - mean(test_bos$medv))^2)
r2 <- 1 - ss_res / ss_tot

cat('RMSE:', round(rmse, 3))
cat('R2:', round(r2, 3))

理解度チェック

prune(tree, cp = best_cp)を呼び出す目的を最もよく説明している文はどれですか。

決定木のまとめ

「決定木 — アンサンブルの基礎」の重要ポイント:

  • 木は特徴量空間を再帰的に分割します。分割にはジニ基準またはエントロピー基準を使用します。
  • rpart(y ~ ., data, method)で木を学習し、printcp()で複雑度表を表示します。
  • 交差検証誤差が最小になるCPを見つけ、その後にprune(tree, cp)を実行します。
  • rpart.plot()で木の構造を可視化します。
  • 深い木は過学習(バイアスが小さく、分散が大きい)し、浅い木は未学習になります。
  • tree$variable.importanceは、分割による改善量の合計に基づいて予測変数を順位付けします。
  • アンサンブル手法(ランダムフォレスト、ブースティング)は、単一の木の不安定性を克服します。
# Standard rpart workflow
tree <- rpart(y ~ ., data = train, method = 'anova',
              control = rpart.control(cp = 0.001))

best_cp <- tree$cptable[which.min(tree$cptable[, 'xerror']), 'CP']
pruned  <- prune(tree, cp = best_cp)

test_pred <- predict(pruned, newdata = test)
rmse <- sqrt(mean((test_pred - test$y)^2))
cat('Pruned Tree RMSE:', rmse)

よくある質問

「決定木:アンサンブルの基礎」レッスンは無料ですか?

はい。「決定木:アンサンブルの基礎」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、R Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 R Academyコースには全4レッスンが含まれています。

「決定木:アンサンブルの基礎」で何を学びますか?

rpart で決定木を構築・可視化し、バイアスと分散のトレードオフを理解します。 ブラウザで直接実行するハンズオンコードでR Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

R Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのR Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「決定木:アンサンブルの基礎」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このR Academyレッスンでコードを書いて実行できますか?

はい。すべてのR Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 決定木:アンサンブルの基礎
  2. ranger によるランダムフォレスト
  3. xgboost による勾配ブースティング
  4. 特徴量の重要度とモデルの解釈
← R Academyに戻る