データの性質で選ぶナイーブベイズのサブタイプ
はじめに
テキスト分類のベースラインにナイーブベイズを使おうとScikit-learnを開くと、MultinomialNB、BernoulliNB、GaussianNB、ComplementNBと4つのクラスが並んでいて、どれを選ぶかでまず手が止まります。名前から違いを推測しにくいうえ、どれを選んでも一応は学習が通ってしまうため、データに合わないクラスを使っていても気づきにくいのが厄介なところです。
4つの違いは、各特徴量の分布に何を仮定するかにあります。単語の出現回数のようなカウントデータならMultinomial、単語が出たか出ないかの二値ならBernoulli、連続値ならGaussian、クラスの偏りが大きいカウントデータならComplementという対応が基本です。この対応がなぜ成り立つのかを、最小限のコード例と直感的なとらえ方で整理します。理論の導出には立ち入らず、モデル選択の判断に必要な範囲に絞ります。
対象読者:
- ナイーブベイズの基本的な理論は理解しているが、Scikit-learnでの実装やクラスの使い分けに迷っている方
- テキスト分類などのタスクで、どのナイーブベイズモデルを選択すべきか、その判断基準を知りたい方
記事のポイント:
- Scikit-learnで提供される4つのナイーブベイズクラスの役割と適用場面が整理できる
- テキストデータの前処理(
CountVectorizerなど)とナイーブベイズモデルの組み合わせがわかる - 各モデルの背後にある考え方を、票の集計や減点方式といった直感的な形でつかめる
ナイーブベイズの基本
4つのクラスに共通する土台から確認します。ナイーブベイズは、ベイズの定理に基づき、特徴量を持つデータがクラスに属する確率を最大化して分類します。中心となる式は次の通りです。
この式は2つの仮定の上に立っています。特徴量同士が互いに独立だという「ナイーブな」仮定と、クラスが与えられたときの各特徴量の分布の仮定です。
Scikit-learnの4つのクラスで異なるのは後者のです。単語の出現回数のようなカウントデータなら多項分布を、特徴の有無のような二値データならベルヌーイ分布を、連続値ならガウス分布を置きます。この分布仮定の違いが、各クラスの得意な領域を決めています。
4つのクラスの役割と使いどころ
MultinomialNB:カウントデータの王道
MultinomialNBは、単語の出現回数のような、非負の整数で表されるカウントデータに最も適しています。テキスト分類でCountVectorizerと組み合わせるときの第一候補です。
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
vec = CountVectorizer(max_features=1000, stop_words='english')
Xtr = vec.fit_transform(X_train_text)
Xte = vec.transform(X_test_text)
clf = MultinomialNB(alpha=1.0).fit(Xtr, y_train)
pred = clf.predict(Xte)
動きは単語による票の集計と考えると分かりやすく、各単語が出現回数に応じて特定のクラスに票を投じます。パラメータalphaはラプラススムージングを制御し、学習データに一度も出現しなかった単語にも最低限の票を与えることで、ゼロ頻度の問題に対応し過学習を防ぎます。
BernoulliNB:特徴の有無で判断する
MultinomialNBが単語の出現回数を見るのに対し、BernoulliNBは単語が出現したかしなかったかの二値(バイナリ)特徴を扱います。特徴量の値は0か1のみを想定するため、CountVectorizerにはbinary=Trueを指定します。
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import BernoulliNB
# binary=Trueで特徴量を0/1に変換
vec = CountVectorizer(max_features=1000, stop_words='english', binary=True)
Xtr = vec.fit_transform(X_train_text)
Xte = vec.transform(X_test_text)
clf = BernoulliNB(alpha=1.0).fit(Xtr, y_train)
各特徴(単語)は、文書中に存在するかどうかで一票だけを投じ、出現回数は考慮されません。文章の長さによらず特定の単語の存在自体が手がかりになるタスク、例えば短文のテキスト分類で効果を発揮することがあります。
GaussianNB:連続値を正規分布で捉える
先の2つが主にテキストデータを想定するのに対し、GaussianNBは連続値(実数)を扱います。各クラスにおける特徴量の分布が正規分布(ガウス分布)に従うと仮定するため、Irisデータセットの花弁の長さのように、正規分布に近似できる連続値が対象になります。
from sklearn.naive_bayes import GaussianNB
clf = GaussianNB().fit(X_train_cont, y_train)
pred = clf.predict(X_test_cont)
クラスごとに特徴量の平均と分散を求め、入力がそのクラスの分布からどれだけ離れているかを評価します。そのクラスの典型的な値に近いほど高いスコアが付きます。
ComplementNB:不均衡データに強い改良版
ComplementNBはMultinomialNBの改良版で、クラスのサンプル数に偏りがある不均衡データに強いのが特徴です。扱うデータはMultinomialNBと同じカウントデータです。
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import ComplementNB
vec = CountVectorizer(max_features=500, stop_words='english')
Xtr = vec.fit_transform(X_train_text)
Xte = vec.transform(X_test_text)
clf = ComplementNB(alpha=1.0).fit(Xtr, y_train)
通常のナイーブベイズが「このデータはクラスにどれだけ当てはまるか」を計算するのに対し、ComplementNBは「このデータはクラスの補集合(以外)にどれだけ当てはまらないか」を計算します。重み付けは次の考え方に基づきます。
ここではクラスの補集合です。補集合で特徴量がよく出現するほどスコアが引かれ、クラスである確率は下がります。つまり、そのクラス以外でよく出る言葉ほど減点が大きくなる減点方式です。
「スポーツ」と「医療」の分類で考えます。「team」や「game」のような一般語はどちらのカテゴリにも現れるため、補集合側でも頻出し、減点が大きくなります。一方、「医療」クラスを採点するときの補集合はスポーツ側の文書で、そこに「virus」や「diagnosis」のような医療専門用語はほとんど出ません。減点が小さいぶん、これらの単語は「医療」クラスの強い証拠として働きます。この仕組みで多数派クラスによく出る一般的な単語の影響が抑えられ、クラス不均衡なデータでも少数派クラスを正しく分類しやすくなります。
前処理とモデル選択の対応表
4つのクラスをデータの前処理方法と合わせて整理すると、モデル選択の指針は次の表に収まります。
| データタイプ | 前処理 | 推奨クラス |
|---|---|---|
| テキスト(出現回数) | CountVectorizer | MultinomialNB / ComplementNB |
| テキスト(出現/非出現) | CountVectorizer(binary=True) | BernoulliNB |
| テキスト(不均衡データ) | CountVectorizer | ComplementNB |
| 連続値 | 標準化など(任意) | GaussianNB |
TF-IDFや相関の強い特徴量をどう扱うか
TF-IDFでベクトル化したデータをGaussianNBに入れること自体はできますが、TF-IDF値が正規分布に従うとは限らず、分布の仮定と噛み合わない場合があります。
独立性の仮定も、現実のデータではほとんど成り立ちません。それでも実用上は十分に高い性能が出ることがよくあります。ただし特徴量間に強い相関がある場合は、他のモデルも検討する価値があります。
alpha(ラプラススムージング)の調整は、データがスパース(ゼロが多い)な場合に特に効きます。実務ではグリッドサーチで最適値を探します。
まとめ
ナイーブベイズは、その名の通り「ナイーブな」独立性仮定を置くシンプルなモデルですが、データの性質に合ったクラスを選べば、テキスト分類を中心に今でも強力なベースラインになります。選び方は、手元の特徴量がカウントか、二値か、連続値かの見極めから始まります。カウントならMultinomialNB、クラスの偏りが大きいならComplementNB、単語の有無だけが効くならBernoulliNB、連続値ならGaussianNBという対応です。実務ではまずMultinomialNBをベースラインに置き、混同行列でクラスごとの成績を確認して、少数派クラスの取りこぼしが目立つ場合にComplementNBへ切り替える、という順で試すと判断を誤りにくくなります。