機械学習 〜 テキスト分類（ナイーブベイズ分類器） 〜

今回は scikit-learn を使ったナイーブベイズ分類器によるテキスト分類を行います。
モデルは以前投稿した[多項分布](https://qiita.com/fujin/items/bd58fc7a93dc6e001045#%E3%83%99%E3%83%AB%E3%83%8C%E3%83%BC%E3%82%A4%E5%88%86%E5%B8%83%E3%83%A2%E3%83%87%E3%83%AB-bernoulli-naive-bayes)を使用します。


## データセット

テキストのデータセットは、scikit-learn に用意されているニュースデータセットを利用します。
このデータには、ニュースのテキストデータと分類される20種類のグループが格納されています。


# 実装コード

### インポート

各種ライブラリをインポートします。

```python
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import  fetch_20newsgroups
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import make_pipeline
```

### データセット準備

sklearn.datasets の ```fetch_20newsgroups()``` を使いデータ取得を行います。

- データ取得

```python
data = fetch_20newsgroups()
```

- 分類グループ名表示

以下のように20種類のグループに分類されています。
コンピューターや宇宙などのグループがあります。

```python
print(data.target_names)

> ['alt.atheism',
 'comp.graphics',
 'comp.os.ms-windows.misc',
 'comp.sys.ibm.pc.hardware',
 'comp.sys.mac.hardware',
 'comp.windows.x',
 'misc.forsale',
 'rec.autos',
 'rec.motorcycles',
 'rec.sport.baseball',
 'rec.sport.hockey',
 'sci.crypt',
 'sci.electronics',
 'sci.med',
 'sci.space',
 'soc.religion.christian',
 'talk.politics.guns',
 'talk.politics.mideast',
 'talk.politics.misc',
 'talk.religion.misc']
```

- 学習・テストデータを取得

トレーニングと評価用データを取得します。

```python
train = fetch_20newsgroups(subset='train')
test = fetch_20newsgroups(subset='test')
```

- データ件数

データ件数は1万件以上あります。

```python
print("Train Data Count =", len(train.data))
print("Test Data Count =", len(test.data))

> Train Data Count = 11314
  Test Data Count = 7532
```

- データの中身を確認

タイトルや本文などのテキストデータが格納されています。

```python
print(train.data[10][:500])

> From: ******.*** (Irwin Arnstein)
Subject: Re: Recommendation on Duc
Summary: What's it worth?
Distribution: usa
Expires: Sat, 1 May 1993 05:00:00 GMT
Organization: CompuTrac Inc., Richardson TX
Keywords: Ducati, GTS, How much? 
Lines: 13

I have a line on a Ducati 900GTS 1978 model with 17k on the clock.  Runs
very well, paint is the bronze/brown/orange faded out, leaks a bit of oil
and pops out of 1st with hard accel.  The shop will fix trans and oil 
leak.  They sold the bike t
```



### テキストデータのベクトル化

テキストデータはそのまま特徴量としては使えないため、
文書中に含まれる単語の重要度を評価する手法の1つである
[TF-IDF](https://qiita.com/fujin/items/b1a7152c2ec2b4963160)(索引語頻度逆文書頻度)という手法を使い、特徴量を算出します。

この算出には sklearn に用意されている ```TfidfVectorizer``` クラスを使います。

※パイプライン内で使用します。

### パイプライン（データ前処理＋モデル生成）

先ほどの TF-IDF(TfidfVectorizer) と ナイーブベイズ分類器(MultinomialNB) の処理を
scikit-learn のパイプラインを使ってまとめて処理します。
パイプラインは前処理を行ったデータをモデルに流し込んで使うなどの一連の処理を
簡単に扱う事が出来るとても便利な機能になります。

```python
model = make_pipeline(TfidfVectorizer(), MultinomialNB())
```

### 学習実行

パイプラインにて、入力テキストデータに対して TF-IDF の特徴量算出処理が行われ、
その特徴量が MultinomialNB の入力データとして学習が実行されます。

```python
model.fit(train.data, train.target)
```

### 評価

作成したモデルを使い、評価を実行します。

```python
print('Train accuracy = %.3f' % model.score(train.data, train.target))
print(' Test accuracy = %.3f' % model.score(test.data, test.target))

>Train accuracy = 0.925
 Test accuracy = 0.773
```

精度は、トレーニングデータをそのまま使った場合は、```0.925```
評価データを使った場合では、```0.773``` となりました。
まずまずの精度となりました。

### 予測相関

テストデータの予測ラベルと正解ラベルの一致度を相関図で確認してみます。

```python
# 表示サイズ
plt.rcParams['figure.figsize'] = (15.0, 15.0)

from sklearn.metrics import confusion_matrix
mat = confusion_matrix(test.target, labels)
sns.heatmap(mat.T, square=True, annot=True, fmt='d', cbar=False,
            xticklabels=train.target_names, yticklabels=train.target_names)
plt.xlabel('true label')
plt.ylabel('predicted label')
```


![2019_03_text_vector_s3.png](https://qiita-image-store.s3.amazonaws.com/0/134550/4123d4ef-866d-3043-778d-92529562ea03.png)

概ね正解しているようですが、`soc.religion.christian`(キリスト教)のグループ分類予測が
`alt.atheism`(無神論)と `talk.religion.misc`(宗教:その他)と混同しているようです。


### 予測

次に、任意のテキストを入力データとして予測を行ってみます。
まず、予測メソッドを定義します。

```python
def predicted_group(s, train=train, model=model):
    pred = model.predict([s])
    return train.target_names[pred[0]]
```

予測を実行します。
予測結果は以下の通りです。

```python
predicted_group('A new Mac book was released.')
> 'comp.sys.mac.hardware'
```

```python
predicted_group('I carry a gun for self-defense')
> 'talk.politics.guns'
```

```python
predicted_group('At 2:32 a.m. EST, Crew Dragon undocked from the International Space Station to begin the final phase of its uncrewed Demo-1 flight test.')
> 'sci.space'
```

それとなく予測は出来ているようです。

<br>

以上、今回は scikit-learn を使ったナイーブベイズ分類器によるテキスト分類を行いました。

<br>