ナイーブベイズは、ベイズの定理と「クラスが決まったとき、特徴量同士は独立に振る舞う」という仮定を使って分類する古典的な機械学習手法です。「ナイーブ(naive、素朴)」という名前は、この独立仮定が現実のデータではかなり大胆な単純化であることに由来します。とはいえ、計算が速く、少ない実装量で動き、特にテキスト分類では今でも有用なベースラインになります。リハビリテーション領域の医学研究では、カルテ記述や退院時サマリーのスクリーニング、少数例データでの比較用モデルとして使いやすい手法です[1]。
// 01 · LEARN OUTCOMESこの記事でわかること
読了後、次の4点を臨床研究の文脈で説明できるようになります。
- ベイズの定理を、診断における事前確率→事後確率の更新として説明できる
- 「ナイーブな独立仮定」が何を意味し、なぜ計算を単純にするかを理解できる
- 3つのバリアント(Gaussian / Multinomial / Bernoulli)を使い分けられる
- テキスト分類・スクリーニングで使う場面と、避けるべき場面を判断できる
// 02 · CONCLUSIONまず結論
// 03 · FIGURE直感的な図解
まず、ベイズの定理を「事前確率を、観測した情報で事後確率に更新する」という形で見てみます。診断や予後予測で、臨床家が日常的に行っている考え方に近いものです。
続いて、「ナイーブな独立仮定」を図で見ます。複数の特徴量がある場合、本来は特徴量の組み合わせ全体を考える必要がありますが、ナイーブベイズではそれぞれを独立とみなし、確率の積に分解します。
3つ目は、3つのバリアント(Gaussian / Multinomial / Bernoulli)の使い分けです。基本的には、特徴量の型に合わせて選びます。
// 04 · CLINICAL医療・リハビリでの具体例
ナイーブベイズが使いやすい場面と、注意が必要な場面を、リハビリテーション領域の研究例で整理します。
退院時サマリーやカルテ記述から、「追加のリハ評価が必要そうか」を自動分類する場面を考えます。「歩行困難」「ADL低下」「嚥下困難」などの単語頻度を特徴量にすると、MultinomialNB を使いやすくなります。深層学習ほど複雑ではありませんが、テキスト分類のベースラインとして実装しやすく、少ないデータでも比較的試しやすい方法です[2]。
「高血圧あり/なし」「糖尿病あり/なし」「脳梗塞既往あり/なし」のような2値特徴量から、合併症リスクやスクリーニング対象を分類する場面では BernoulliNB が候補になります。単独で最終判断に使うというより、ロジスティック回帰などと比較するシンプルなベースラインとして位置づけると使いやすいです。
希少疾患リハ研究で N=60、変数が8個程度という状況では、複雑なモデルは不安定になりやすくなります。GaussianNB はクラスごとに各変数の平均と分散を推定するだけなので、比較的安定しやすいです。しかし、少数例でも必ず安定するわけではないので注意が必要です。k近傍法(kNN) や 正則化付きロジスティック回帰 と並べて評価するのが定石です。
FIM の運動項目13個と認知項目5個は互いに相関しやすく、独立とは考えにくい変数群です。これらをそのままナイーブベイズに入れると、同じような情報を何度も数える形になり、予測確率が極端に高く出ることがあります。「自宅退院 99%」のような過剰に自信を持った確率が出た場合、順位づけは参考になっても、確率値そのものは慎重に扱う必要があります。
ナイーブベイズは分類器としては有用でも、確率予測は過剰に0または1へ寄りやすいことがあります。相関する特徴量を独立とみなして掛け算するため、同じ証拠を重複して数えてしまうことがあるからです。確率値を臨床意思決定に使う場合は、Calibration plot で確認し、必要に応じて確率校正を行います。
// 05 · THEORY数式・理論
ナイーブベイズの数学的構造を、ベイズの定理 → 独立仮定 → 3バリアントの3点で整理します。
ベイズの定理
# 基本形
P(C | x) = P(x | C) · P(C) / P(x)
# 分類問題への適用
予測クラス = argmax_C P(C | x)
= argmax_C P(x | C) · P(C) / P(x)
= argmax_C P(x | C) · P(C)
↑
P(x) は C に依存しない定数なので無視できる
# つまり、最大化したいのは:
posterior ∝ likelihood × prior
ナイーブな独立仮定
多変量の同時分布 P(x|C) は、変数が増えると指数的にパラメータ数が増えます。これを「独立仮定」で線形に抑えるのがナイーブベイズの核心です。
# 真の同時分布(計算困難)
P(x | C) = P(x_1, x_2, ..., x_d | C)
# ナイーブな独立仮定(計算可能)
P(x | C) ≈ P(x_1 | C) · P(x_2 | C) · ... · P(x_d | C)
= Π_j P(x_j | C)
↑
各変数を独立に推定して積を取る
# 予測
ŷ = argmax_C P(C) · Π_j P(x_j | C)
# 数値安定性のため log で計算
ŷ = argmax_C log P(C) + Σ_j log P(x_j | C)
3つのバリアントの確率モデル
# GaussianNB: 連続値特徴量
P(x_j | C) = (1 / √(2π σ²_jc)) · exp(−(x_j − μ_jc)² / (2σ²_jc))
- 訓練時:クラスごとに μ_jc, σ_jc を推定
- 予測時:正規分布の確率密度を計算
# MultinomialNB: カウントデータ(単語頻度等)
P(x | C) ∝ Π_j θ_jc^(x_j)
- θ_jc:クラス C で特徴量 j が出現する確率
- 訓練時:θ_jc = (count_jc + α) / (Σcount_c + α·V)
↑
Laplace 平滑化(α=1 が標準)
# BernoulliNB: 2値特徴量
P(x | C) = Π_j θ_jc^(x_j) · (1 − θ_jc)^(1−x_j)
- 各特徴量の有無を独立に評価
Laplace 平滑化(なぜ必要か)
テキスト分類で「訓練データに一度も出現しなかった単語」があると、確率が 0 になり、log を取ると −∞ に発散します。これを防ぐのが平滑化です。
# 素朴な推定
θ_jc = count_jc / Σcount_c
→ count_jc = 0 のとき θ_jc = 0
→ 予測時に確率の積が 0 → 全体が崩壊
# Laplace 平滑化(α=1 の例)
θ_jc = (count_jc + 1) / (Σcount_c + V)
↑ ↑
擬似カウント追加 語彙サイズで正規化
→ 0 にならない
計算量の利点
# 訓練:O(N · d)
- 各クラス・各特徴量で平均などを計算するだけ
- 反復学習なし(解析的に決まる)
# 予測:O(d · K)
- d 個の確率を K クラス分かけるだけ
- ニューラルネットや SVM より圧倒的に高速
★ 大規模なテキスト分類でも、比較的高速に訓練しやすい
// 06 · IMPLEMENTATION · PYTHON実装
scikit-learn での3バリアントの実装をします。データの型に合わせてモデルを選ぶのが重要です。
import numpy as np
import pandas as pd
from sklearn.naive_bayes import GaussianNB, MultinomialNB, BernoulliNB
from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score, classification_report
# ============================================
# ① GaussianNB:連続値の予後予測ベースライン
# ============================================
df = pd.read_csv("rehab_cohort.csv")
X = df[["age", "fim_motor_admission", "fim_cog_admission",
"onset_days", "nihss"]]
y = df["discharge_home"]
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, stratify=y, random_state=42
)
# GaussianNBでは標準化は必須ではないが、前処理を統一したい場合はPipelineで行う
gnb = GaussianNB()
gnb.fit(X_train, y_train)
y_proba = gnb.predict_proba(X_test)[:, 1]
print(f"GaussianNB AUC: {roc_auc_score(y_test, y_proba):.3f}")
# クラスごとの μ と σ を確認(モデルの中身)
print("Class means:")
print(pd.DataFrame(gnb.theta_, columns=X.columns,
index=["facility", "home"]))
# ============================================
# ② MultinomialNB:診療記録のテキスト分類
# ============================================
# サンプル: カルテ要約から「リハ依頼必要」を分類
documents = [
"歩行困難 ADL 低下 嚥下困難",
"意識清明 自立歩行 ADL 自立",
"片麻痺 失語 リハ介入必要",
"順調 退院予定 リハ完了",
# ...
]
labels = [1, 0, 1, 0] # 1=リハ依頼, 0=不要
# Bag-of-Words ベクトル化
vectorizer = CountVectorizer()
X_text = vectorizer.fit_transform(documents)
mnb = MultinomialNB(alpha=1.0) # Laplace平滑化
mnb.fit(X_text, labels)
# 新規テキストの分類
new_doc = ["麻痺 ADL 介助 リハ"]
new_vec = vectorizer.transform(new_doc)
print(mnb.predict_proba(new_vec)) # [[P(no), P(yes)]]
# Pipeline 化(本番用)
text_pipe = Pipeline([
("vectorizer", TfidfVectorizer(max_features=1000)),
("nb", MultinomialNB(alpha=1.0)),
])
# ============================================
# ③ BernoulliNB:既往歴(0/1)からの予測
# ============================================
# サンプル: 既往歴の有無
medical_history = pd.DataFrame({
"hypertension": [1, 0, 1, 1, 0],
"diabetes": [1, 0, 1, 0, 0],
"stroke": [0, 0, 1, 1, 0],
"afib": [0, 0, 0, 1, 0],
})
complication = [1, 0, 1, 1, 0]
bnb = BernoulliNB(alpha=1.0)
bnb.fit(medical_history, complication)
new_patient = pd.DataFrame({
"hypertension": [1], "diabetes": [1],
"stroke": [0], "afib": [0],
})
print(bnb.predict_proba(new_patient))
# ============================================
# ④ 3手法の性能比較(同じデータで)
# ============================================
from sklearn.linear_model import LogisticRegression
models = {
"GaussianNB": GaussianNB(),
"LogisticRegression": LogisticRegression(max_iter=1000),
}
for name, model in models.items():
model.fit(X_train, y_train)
proba = model.predict_proba(X_test)[:, 1]
print(f"{name:22} AUC: {roc_auc_score(y_test, proba):.3f}")
# どちらが良いかはデータ次第。ベースラインとして比較する
# ============================================
# ⑤ Calibration 確認(NB は過剰確信しやすい)
# ============================================
from sklearn.calibration import calibration_curve
prob_true, prob_pred = calibration_curve(
y_test, y_proba, n_bins=10
)
# 理想は対角線。NB は端(0や1)に偏ることが多い
# → 確率を意思決定に使う場合は CalibratedClassifierCV で校正を検討
from sklearn.calibration import CalibratedClassifierCV
calibrated = CalibratedClassifierCV(GaussianNB(), method="isotonic", cv=5)
calibrated.fit(X_train, y_train)
y_proba_cal = calibrated.predict_proba(X_test)[:, 1]
重要: ナイーブベイズでは、分類の順位づけは役に立つ一方で、予測確率が異常に高く、または低く出ることがあります。確率そのものを臨床意思決定に使う場合は、CalibratedClassifierCV などで校正を検討し、Calibration plot で確認します。
// 07 · MYTHSよくある誤解
- 独立仮定が成立しないなら、NBは使い物にならない
- 誤り。独立仮定は厳密には成立しないことが多いですが、それだけで直ちに使えないわけではありません。特にテキスト分類では、確率値そのものは歪んでも、クラスの順位づけが実用的に機能することがあります。
- NB の確率予測は他と同じく信頼できる
- 誤り。ナイーブベイズでは、予測確率が0または1に近づきすぎることがあります。確率を意思決定に使う場合は、Calibration plot で確認し、必要に応じて CalibratedClassifierCV などで校正します。
- 3つのバリアントはどれを選んでも同じ結果になる
- 違う。データの型と合わないバリアントを使うと、性能や解釈が悪くなります。連続値中心なら GaussianNB、単語頻度などのカウントなら MultinomialNB、0/1特徴量なら BernoulliNB を選ぶのが基本です。
- テキスト分類なら NB より深層学習(BERT等)の方が常に良い
- 場合によります。深層学習は強力ですが、学習データが少ない場合や、まずスクリーニング用の軽いモデルを作りたい場合には、ナイーブベイズが十分なベースラインになることがあります。複雑な手法を使う前に、シンプルな方法と比較しておくと研究設計としても説明しやすくなります。
// 08 · WRITING論文での書き方
Methods に記述すべき項目
- ナイーブベイズを使う理由(テキスト分類 / ベースライン / スクリーニングなど)
- 選択したバリアント(Gaussian / Multinomial / Bernoulli)とその理由
- 平滑化パラメータ α(Laplace 平滑化)
- テキスト分類なら Bag-of-Words / TF-IDF などのベクトル化方法
- 独立仮定が結果に与える影響(Discussion で言及)
- Calibration の評価結果(予測確率を解釈する場合)
Methodsの書き出し例
"As a simple baseline classifier, we trained a Gaussian Naive Bayes
(GaussianNB) model. This model assumes conditional independence
among predictors given the class. Because this assumption may not
hold strictly in clinical data, for example when FIM motor and
cognitive scores are correlated, we interpreted the model mainly
as a baseline comparator. We evaluated discrimination using AUC
and assessed calibration using reliability diagrams. Because
Naive Bayes may produce overconfident probability estimates, we
also examined post-hoc calibration using CalibratedClassifierCV
with 5-fold cross-validation."
査読者が指摘しやすい点
- 「独立仮定の妥当性が議論されていない」
- 「Calibration を確認していない(NB は過剰確信しやすい)」
- 「バリアント(Gaussian/Multinomial/Bernoulli)の選択理由が不明」
- 「テキスト分類で TF-IDF を使ったか Bag-of-Words かが不明確」
// 09 · CHECKLISTチェックリスト
ナイーブベイズの使い方を点検する6項目。
- 01ナイーブベイズを使う目的(テキスト分類 / ベースライン / スクリーニング)が明確
- 02データの型と一致するバリアント(Gaussian/Multinomial/Bernoulli)を選択
- 03Laplace 平滑化のパラメータ α を Methods に明記
- 04独立仮定の影響を Discussion で議論した
- 05Calibration を評価し、必要なら校正(CalibratedClassifierCV)した
- 06他のアルゴリズム(LogReg、勾配ブースティング)と性能比較した
// 10 · QUIZミニクイズ
-
Q1カルテ記述から「リハ依頼が必要か」を分類したい。最も適切なバリアントは?
- GaussianNB(連続値用)
- MultinomialNB(カウント用)
- BernoulliNB(2値用)
- どれでも同じ
SHOW ANSWER
B. 単語頻度はカウントデータなので MultinomialNB が使いやすいです。Bag-of-Words や TF-IDF で特徴量化してから適用します。BernoulliNB は「単語が出たかどうか」だけを見る方法で、頻度情報は使いません。 -
Q2NB が「ナイーブ」と呼ばれる根拠は?
- アルゴリズムが古いから
- 特徴量間の条件付き独立を仮定するから
- ベイズの定理を使うから
- 過学習しやすいから
SHOW ANSWER
B. 「ナイーブ(素朴)」とは、クラスが決まったときに特徴量同士が条件付き独立である、と仮定しているためです。この単純化のおかげで計算は速くなりますが、予測確率は歪むことがあります。 -
Q3NB の最も注意すべき弱点は?
- 分類精度が常に低い
- 確率予測が過剰確信する(0や1に偏る)
- 計算が遅い
- 小サンプルでは使えない
SHOW ANSWER
B. 相関する特徴量を独立とみなすことで、同じ証拠を重複して数え、確率が過剰に0または1へ近づくことがあります。確率値を意思決定に使う場合は、Calibrationを確認し、必要なら校正します。
// REF参考文献
- Domingos P, Pazzani M. On the optimality of the simple Bayesian classifier under zero-one loss. Mach Learn 1997;29:103-130.
- McCallum A, Nigam K. A comparison of event models for naive Bayes text classification. AAAI-98 Workshop on Learning for Text Categorization 1998:41-48.