決定木は、症例を条件で順に分けるモデルです。「入院時 FIM が高いか」「年齢が高いか」のように、臨床で日常的に行う判断に近い形で予測過程を読めるのが特徴です。一方、深く伸ばしすぎると訓練データの細部まで覚えてしまいます。本稿では、分岐・剪定・過学習・実装上の注意を整理します。
本稿は第3部「医療AI・機械学習アルゴリズム図鑑」の第7記事です。 ロジスティック回帰 のような係数モデルと比べ、決定木は if-then 形式で読める点が強みです。ただし単一木は不安定で、後続の アンサンブル学習・ ランダムフォレスト・ 勾配ブースティング の土台として理解するのが実用的です。木の深さと汎化性能の関係は 14·01 過学習デモ、評価設計は 14·02 交差検証デモ で体感できます。
// 01 · LEARN OUTCOMESこの記事でわかること
- 決定木が if-then 形式で症例を分岐する仕組みを説明できます。
- Gini、エントロピー、MSE などの分割基準を理解できます。
- max_depth、min_samples_leaf、剪定で過学習を抑える考え方を説明できます。
- Pipeline と交差検証で、リーケージを避けた実装ができます。
// 02 · CONCLUSIONまず結論
// 03 · FIGURE直感的な図解
図1では、最初の分岐が root node です。そこから FIM・年齢・麻痺重症度などで症例を分けていき、最後にたどり着くのが leaf node。分類なら、その葉で最も多いクラスを出力し、回帰ならその葉の平均値を出力します。
図2では、木の深さを変えたときの性能を比べます。訓練データでは深い木ほどよく当たりますが、検証データでは途中で頭打ち。さらに深くすると未知データへの性能が落ち始めます。これは 過学習 の典型例です。
// 04 · CLINICALリハ研究での使いどころ
FIM・年齢・家族介護力・認知機能から、自宅退院と施設退院を分ける場面。決定木なら「FIM が一定以上で、家族支援あり」のように、分岐条件を文章化しやすいのが利点です。一方、施設ごとの退院支援体制を反映してしまうこともあるため、結果の臨床的読みには注意します。
NIHSS・年齢・併存疾患・意識障害などから、転帰や重症度を層別化する場面です。決定木は臨床で共有しやすい分岐を作れます。ただし単一木の分岐はデータの分割で揺れやすいので、GroupKFold や外部検証で安定性を確認します。
入院時 FIM 歩行項目・SIAS 下肢・認知 FIM・10m 歩行などから、退院時歩行自立を予測します。決定木は非線形な閾値や交互作用を自然に扱えるため、「同じ麻痺重症度でも認知機能で分岐が変わる」といった構造を表現しやすくなります。
BBS・TUG・服薬数・起立性低血圧・既往転倒などから転倒リスクを分類する場面です。決定木はスクリーニングの候補ルールを可視化できる一方、特徴量重要度は因果効果ではありません。介入対象の決定には、別の臨床検討が必要です。
// 05 · THEORY数式・理論
決定木の基本
決定木は、データを条件で再帰的に分けていきます。各分岐では「どの特徴量で、どの閾値にすれば、分けた後の群が最も純粋になるか」を探します。分類木と回帰木をまとめて CART と呼びます[1]。
分類では、葉の中に同じクラスが集まるほど良い分割。回帰では、葉の中の目的変数のばらつきが小さいほど良い分割です。この考え方で、閾値の組み合わせを自動で探索します。C4.5 などの古典的な木も同じ系譜にあります[2]。
分類木の分割基準
# Gini impurity
Gini = 1 - sum_k p_k^2
# Entropy
Entropy = - sum_k p_k * log2(p_k)
# Information gain
Gain = impurity(parent) - weighted_impurity(children)
p_k: node 内で class k が占める割合
Gini もエントロピーも、ノードの混ざり具合を表す指標です。1つのクラスだけなら不純度は低く、複数のクラスが均等に混ざるほど高くなります。scikit-learn では、分類で Gini か entropy を選べます[5]。
回帰木の分割基準
# Regression tree split criterion
MSE = (1 / n) * sum_i (y_i - mean(y))^2
# split の目的
Choose split that minimizes:
weighted_MSE(left_child, right_child)
回帰木では、各葉の平均値が予測値になります。退院時 FIM 合計点を予測するなら、似た症例を同じ葉に集めるほど MSE が下がります。ただし、葉の症例数が少ないと平均値そのものが不安定になります。
木の深さと剪定
# Cost-complexity pruning
R_alpha(T) = R(T) + alpha * |T|
R(T): training error of tree T
|T| : number of leaf nodes
alpha: tree complexity penalty
深い木は、症例ごとの細かい違いまで覚えてしまいます。訓練データには合いやすい一方、新しい症例では性能が落ちる原因に。max_depth・min_samples_leaf・max_leaf_nodes・ccp_alpha で木の複雑さを制御します。
特に医療データは N=100〜1,000 程度の研究が多いため、葉の最小症例数を小さくしすぎると、1施設・1病棟の偶然を拾うことがあります。単一木では、見やすさと安定性の両立が常に課題です[4]。
// 06 · IMPLEMENTATIONPython 実装例
以下は教育用の仮想データを使う例です。実データを扱う場合は、個人情報保護・倫理審査・施設ルール・データ利用規約を確認します。決定木は標準化を必要としませんが、欠測補完とカテゴリ変数処理は Pipeline 内で行います。
import pandas as pd
import numpy as np
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.metrics import roc_auc_score, make_scorer
from sklearn.model_selection import GridSearchCV, StratifiedKFold, cross_validate
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
from sklearn.tree import DecisionTreeClassifier, plot_tree
import matplotlib.pyplot as plt
# ------------------------------------------------------------
# Educational example only.
# Use anonymized data and follow institutional rules.
# Do not fit preprocessors before train/test split or CV.
# ------------------------------------------------------------
DATA_PATH = "example_rehab_dataset.csv"
TARGET = "home_discharge"
# Example columns:
# age, sex, admission_fim_motor, admission_fim_cognition,
# fim_walk_admission, sias_leg, nihss_total, family_support,
# tug_seconds, bbs_total, medication_count, home_discharge
df = pd.read_csv(DATA_PATH)
numeric_features = [
"age",
"admission_fim_motor",
"admission_fim_cognition",
"fim_walk_admission",
"sias_leg",
"nihss_total",
"tug_seconds",
"bbs_total",
"medication_count",
]
categorical_features = [
"sex",
"family_support",
]
X = df[numeric_features + categorical_features]
y = df[TARGET]
numeric_transformer = Pipeline(
steps=[
("imputer", SimpleImputer(strategy="median")),
]
)
categorical_transformer = Pipeline(
steps=[
("imputer", SimpleImputer(strategy="most_frequent")),
("onehot", OneHotEncoder(handle_unknown="ignore")),
]
)
preprocess = ColumnTransformer(
transformers=[
("num", numeric_transformer, numeric_features),
("cat", categorical_transformer, categorical_features),
]
)
base_tree = DecisionTreeClassifier(
max_depth=4,
min_samples_leaf=20,
random_state=42,
)
pipe = Pipeline(
steps=[
("preprocess", preprocess),
("model", base_tree),
]
)
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_validate(
estimator=pipe,
X=X,
y=y,
cv=cv,
scoring={
"auc": "roc_auc",
"accuracy": "accuracy",
"brier": "neg_brier_score",
},
return_train_score=True,
)
print("CV AUC:", scores["test_auc"].mean(), scores["test_auc"].std())
print("CV accuracy:", scores["test_accuracy"].mean())
print("CV Brier:", -scores["test_brier"].mean())
param_grid = {
"model__max_depth": [2, 3, 4, 5, 6, None],
"model__min_samples_leaf": [5, 10, 20, 30],
"model__ccp_alpha": [0.0, 0.001, 0.005, 0.01],
}
grid = GridSearchCV(
estimator=pipe,
param_grid=param_grid,
scoring="roc_auc",
cv=cv,
n_jobs=-1,
refit=True,
)
grid.fit(X, y)
print("Best parameters:", grid.best_params_)
print("Best CV AUC:", grid.best_score_)
best_pipe = grid.best_estimator_
# Extract feature names after preprocessing.
onehot = best_pipe.named_steps["preprocess"].named_transformers_["cat"].named_steps["onehot"]
cat_names = onehot.get_feature_names_out(categorical_features)
feature_names = numeric_features + list(cat_names)
model = best_pipe.named_steps["model"]
importance = pd.Series(model.feature_importances_, index=feature_names)
importance = importance.sort_values(ascending=False)
print(importance.head(15))
plt.figure(figsize=(18, 8))
plot_tree(
model,
feature_names=feature_names,
class_names=["not_home", "home"],
filled=True,
rounded=True,
max_depth=3,
)
plt.tight_layout()
plt.show()
この例では、欠測補完と OneHotEncoder を Pipeline に含めているため、各 fold の訓練データだけで前処理が fit されます。全データで補完してから CV する流れは避けます。決定木では StandardScaler は使っていません。分岐は値の大小で決まるため、単位変換に比較的影響されにくいからです。
実装上の鍵は max_depth と min_samples_leaf です。max_depth は木の深さの上限、min_samples_leaf は各葉に必要な最小症例数。医療データで葉が数例だけになる設定は不安定になりやすいので、AUC だけでなく Brier score や calibration も合わせて確認します。
// 07 · MYTHSよくある誤解
- 誤解: 決定木は解釈が容易だから医療で安全
- 読めることと、安定していることは別問題です。fold が変わるだけで最初の分岐が変わることもあります。解釈しやすさだけでなく、再現性も合わせて確認します。
- 誤解: 深い木の方が精度が高い
- 訓練データには当たりやすくなりますが、検証データでは過学習で性能が落ちることがあります。max_depth・min_samples_leaf・ccp_alpha を調整します。
- 誤解: 決定木は前処理が一切要らない
- 標準化は基本的に不要ですが、欠測補完・カテゴリ変数処理・外れ値確認は必要です。前処理は Pipeline 内に入れて評価します。
- 誤解: 特徴量重要度は因果効果である
- 特徴量重要度は予測への寄与です。FIM が重要に見えても、FIM を変える介入で転帰が変わるとは限りません。因果を論じるには別の研究設計が必要です。
// 08 · WRITING論文 Methods に書くこと
決定木を論文に書くときは、単に「決定木を用いた」では不足します。どの分割基準を使ったか、木の深さをどう制御したか、どうハイパーパラメータを探索したか。TRIPOD+AI では、モデル開発と評価の透明性が重視されます[6]。
- 目的変数の定義: 自宅退院、歩行自立、FIM 合計点など。
- 説明変数の時点: 入院時、退院前、発症後日数など。
- 前処理: 欠測補完、カテゴリ変数処理、外れ値対応。
- モデル設定: criterion、max_depth、min_samples_leaf、ccp_alpha。
- 評価設計: hold-out、k-fold CV、GroupKFold、多施設外部検証。
- 比較モデル: ロジスティック回帰、正則化線形、単純な臨床ルール。
- 評価指標: AUC、感度、特異度、Brier score、calibration。
- 解釈: 木構造、特徴量重要度、臨床的妥当性の確認。
査読では、単一木の不安定性がよく指摘されます。たとえば、5-fold CV の各 fold で同じ分岐が出るか、bootstrap で root node が安定するかを示すと、説得力が増します。PROBAST+AI の観点では、参加者・予測因子・アウトカム・解析のバイアスと適用可能性を明確にします[7]。
また、決定木の分岐を臨床ルールのように提示する場合は注意します。それは「このデータで得られた予測ルール」であって、他施設や別時期の患者にそのまま当てはまるとは限りません。外部検証や再現性確認を、性能評価とは別に示すと読みやすくなります。
// 09 · CHECKLIST実装前チェックリスト
- 01目的変数は分類か回帰かを明確にした。
- 02説明変数が予測時点で利用可能かを確認した。
- 03欠測補完とカテゴリ処理を Pipeline に入れた。
- 04標準化が不要な理由を Methods で説明できる。
- 05max_depth と min_samples_leaf を探索した。
- 06深い木だけでなく、浅い木も比較した。
- 07ロジスティック回帰などのベースラインと比較した。
- 08特徴量重要度を因果効果として書いていない。
// 10 · QUIZ理解度チェック
-
Q1分類木で Gini 不純度が低い状態として正しいものはどれですか。
- 複数クラスが均等に混ざっている
- 1つのクラスが多く集まっている
- 特徴量の単位がそろっている
- 木の深さが大きい
SHOW ANSWER
B. ノード内で同じクラスが多いほど、不純度は低くなります。 -
Q2決定木で過学習を抑える設定として適切なものはどれですか。
- max_depth を大きくする
- min_samples_leaf を小さくする
- ccp_alpha を調整する
- 全データで補完してから CV する
SHOW ANSWER
C. ccp_alpha は Cost-complexity pruning の強さを調整します。 -
Q3決定木で StandardScaler が基本的に不要な理由はどれですか。
- 分岐が特徴量の大小関係で決まるため
- 決定木は欠測を必ず自動処理するため
- 決定木は確率を必ず正しく較正するため
- 決定木は過学習しないため
SHOW ANSWER
A. 距離計算に基づく SVM や kNN と違い、決定木は閾値分岐が中心です。 -
Q4特徴量重要度の説明として適切なものはどれですか。
- その特徴量の因果効果を示す
- その特徴量の予測への寄与を示す
- 交絡の影響を完全に除く
- 外部妥当性を保証する
SHOW ANSWER
B. 特徴量重要度は予測寄与の指標であり、因果効果ではありません。
// 11 · FAQよくある質問
- 決定木は標準化が必要ですか?
- 基本的に不要です。決定木は特徴量の大小関係で分岐を決めるため、単位スケールの違いに影響されにくい性質があります。一方、欠測補完とカテゴリ変数処理は Pipeline 内で行います。
- 単一の決定木とランダムフォレストの違いは?
- 単一木は読みやすい一方で、データの分割で分岐が変わりやすい不安定さがあります。ランダムフォレスト は多数の木を組み合わせて分散を下げ、汎化性能を高めるアプローチです。
- 特徴量重要度を臨床ルールとしてそのまま使ってよいですか?
- 特徴量重要度は予測への寄与であり、因果効果ではありません。臨床ルールに使うには、外部検証・因果的検討・前向き評価などを別途行う必要があります。
// REF参考文献
- Breiman L, Friedman JH, Olshen RA, Stone CJ. Classification and Regression Trees. Wadsworth, 1984.
- Quinlan JR. Induction of decision trees. Machine Learning 1986;1(1):81-106.
- Quinlan JR. C4.5: Programs for Machine Learning. Morgan Kaufmann, 1993.
- Hastie T, Tibshirani R, Friedman J. The Elements of Statistical Learning. 2nd ed. Springer, 2009.
- Pedregosa F, Varoquaux G, Gramfort A, et al. Scikit-learn: machine learning in Python. Journal of Machine Learning Research 2011;12:2825-2830.
- Collins GS, Moons KGM, Dhiman P, et al. TRIPOD+AI statement: updated guidance for reporting clinical prediction models that use regression or machine learning methods. BMJ 2024;385:e078378.
- Moons KGM, Damen JAA, Kaul T, et al. PROBAST+AI: an updated quality, risk of bias, and applicability assessment tool for prediction models using regression or artificial intelligence methods. BMJ 2025;388:e082505.