ナイーブベイズで自然言語処理(クラス分類)【Pythonとscikit-learnで機械学習:第7回】

自然言語処理のおいて、迷惑メールの識別などで有名なナイーブベイズを用いた、テキストデータの識別手法について、実装・解説します。

本シリーズでは、Pythonを使用して機械学習を実装する方法を解説します。

各アルゴリズムの数式だけでなく、その心、意図を解説していきたいと考えています。

ナイーブベイズは、以下のscikit-learnマップの黒矢印に対応します。

[scikit-learnのマップ]

START→データが50以上→カテゴリーデータ→ラベルありデータ→データ数10万以下→Linear SVC失敗→テキストデータ→[ナイーブベイズ]

まず今回やりたいことの概要を説明します。

今回扱うデータはlivedoorのニュースコーパスから取得した7367個のニュース記事です。

各ニュースは、トピックニュース、Sports Watch、ITライフハック、家電チャネル、MOVIE ENTER、独女通信、エスマックス、livedoor HOMME、Peachyの9カテゴリのいずれかに属しています。

今回やりたいことは、このニュース記事を学習データとテストデータに分けて、ナイーブベイズにより識別器を作成し、テストデータのニュース記事を入力したときに、そのニュース記事が9つのカテゴリのどれに属するのかを判定することです。

そのためには、時系列データのように、テキストデータを扱いやすい数値データへと変換する必要があります。

そこで今回はまず、テキストデータを名詞や動詞、形容詞、助詞などに分けます。

これを形態素解析や、分かち書きと呼びます。

次に学習データの各単語をナンバリングしていきます。

そして各ニュース記事に対して、記事内でのそれぞれの単語の出現数を要素に持つベクトルを生成します。

もし学習データに含まれる単語の数が1万個であれば、1万次元のベクトルとなり、その単語が出現した回数が格納されます。

最後に、この1万次元のベクトルたちをナイーブベイズで分類するという流れを行います。

形態素解析・分かち書き

まずはじめに形態素解析による分かち書きの実装を紹介します。

Pythonによるスクレイピング&機械学習を参考にしています。

データとして、livedoorニュースコーパスの記事を使用します。

livedoorニュースコーパス

ldcc-20140209.tar.gzをダウンロードします。

形態素解析には有名なライブラリとして、MeCabとJanomeがありますが、MeCabはWindowsでは動かしにくいので、Janomeを使用します。

Anaconda Promptを開いて、

でJanomeのライブラリをインストールします。

そして、以下のwakati.pyを実行します。

途中エラー吐く変なファイルがひとつあったので、それは除外しました(smax-6909466.txt)。

少し時間がかかりますが、以上のファイルを実行することで、ニュース記事から名詞、動詞、形容詞だけが分離されます。

(元ニュース)

(分かち書き)

ニュースをベクトルに変換

次に、単語ごとにナンバリングして、ニュース記事をベクトルにします。

この操作をBoW(Bag-of-Words)とも呼びます。

まずはじめの全ニュースの単語を辞書にします。

そして、各ニュースの単語の出現回数をベクトルにします。

今回は100ニュースずつデータを使用します。

このプログラムにより、各ニュースをベクトルにしたtextdata.jsonが生成されます。

時間がまずまずかかります。

ニュースを識別

最後にニュース記事を学習データとテストデータに分割し、ナイーブベイズで学習、識別します。

#解説 3:機械学習で分類・識別する

clf = naive_bayes.MultinomialNB(alpha=0.1, fit_prior=’True’ )

の部分だけ新しいので説明します。

MultinominalNBはナイーブベイズ手法のうちの多項分布を使用したナイーブベイズを指定しています。

alphaは学習時に出てこなかった単語が、テストデータの記事に出てきたときに、生成確率が0になるのを避けるための調整パラメータです。

ちょっと分かりにくいですが、学習データ全てに、「機械学習」という言葉が一切出てこなかった場合に、テストデータに「機械学習」が入った文章はどのクラスに属する確率も0になってしまいます。

それを避けるための微小値です。

(alpha=1をラプラス・スムージング、alpha<1の場合をLidstone smoothingと呼びます)

fit_prior=’True’は、学習データの偏りがあった場合に、それを考慮するかどうかです。

今はTrueなので、偏りがあった場合に考慮しています。

それでは「結局、ナイーブベイズって何をやっていたの?」

ナイーブって日本語では、純朴とか”うぶ”っていう意味で使いますが、

「うぶなベイズって何?」

を説明します。

ナイーブベイズの心

正確な情報は以下をご覧ください。

scikit-learnのナイーブベイズの解説ページ

scikit-learnの多項分布ナイーブベイズの解説ページ

ナイーブベイズのナイーブは、うぶという意味ではなく、”先入観のない”という意味です。

英語のnaiveにはそういう意味もあります。

何に対して先入観がないかというと、

「特徴ベクトルの各要素間に事前知識がなく独立だと仮定する」という意味です。

ちょっと難しくなったので丁寧に説明します。

いまテキスト分類において、文章が単語ごとのベクトルになっています。

ベクトルの要素(各次元)はひとつの単語を現しています。

もしニュースのなかでiPhoneという単語があったとすると、Appleという単語も同じニュースの中で出てくる確率が高いと思われます。

それは私たちがiPhoneはAppleが作っているという事前知識を持っているからです。

こうした事前知識を考慮せず、iPhoneという単語があろうと、なかろうと、同じニュースのなかで、Appleという単語が出現する確率は同じである

(つまりiPhoneとAppleという単語は独立である)

と仮定することがナイーブベイズのnaiveの意味するところです。

これさえ分かれば、あとはニュース記事をベイズ推定に従って分類するだけです。

ベイズ推定とか難しそうですが、今回の多項分布の場合はとても単純です。

例えばラベル1の学習データにiPhoneという言葉が15回出現し、ラベル2では5回だったとします。

そしてテストデータの記事にiPhoneという言葉が出てくれば、ラベル1である確率は75%である、とするだけです。

これを全部の単語について掛け算して、テストデータの記事がどのラベルに属しているっぽいかを判定します。

そのときに、1度も出てきたことがない単語があると、確率0が掛け算されてしまうので、全部のクラスで全部の単語に対して、alphaだけ、出現回数を足しておきます。

式を使って説明しているページでは以下の記事が分かりやすいです。

ナイーブベイズを用いたテキスト分類

以上、Pythonとscikit-learnで学ぶ機械学習入門|第7回:ナイーブベイズによるテキスト分類でした。

次回は、識別器のパラメータチューニングと識別結果の解析手法について解説します。

【目次】Python scikit-learnの機械学習アルゴリズムチートシートを全実装・解説
scikit-learnのアルゴリズムチートマップで紹介されている手法を、全て実装・解説してみました。 ...