少量のテキストデータとSVMを使って、自然文章の分類器を作ったゾ！

#はじめに
勝手なイメージですが、自然言語処理の機械学習と言えば、世間的にはLSTMやトピックモデルなどが挙げられると思います。LSTMやトピックモデルは自然文章のデータが大量にあることで、効果を得られるものです。しかし、ビジネス領域において自然文章のデータを大量に集めることは大変難しいです。
それならば、少量のデータで機械学習できれば、幸せになれる人がいるんじゃないかと考えました。
なので、今回は、少量データで機械学習をして、学習できるのか見たいと思います。

# 今回のやること
以下の技術を用いて、分類器を作ります。

* tfidf
    こちらを参考に勉強させて頂きました。
    http://ailaby.com/tfidf/

* svm（サポートベクターマシン）
    こちらを参考に勉強させて頂きました。
    https://qiita.com/kazuki_hayakawa/items/18b7017da9a6f73eba77

#今回の流れ
##### ① twitterからテキストデータの取得
「機械学習」、「自然言語処理」、「データサイエンティスト」の文字列を含むツイートを100件ずつ取得する。

#####②  テキストデータへのラベル付け
以下のようなルールでラベル付け。（テキストデータ ＝＞ ラベル）
    
* 「機械学習」で検索したテキストデータ　＝＞　機械学習
* 「自然言語処理」で検索したテキストデータ　＝＞　自然言語処理
* 「データサイエンティスト」で検索したテキストデータ　＝＞　データサイエンティスト

#####③ tfidfモデル、tfidfベクトルを作成
取得したデータから名詞、形容詞の単語を抽出し、単語リストを生成。
単語リストからtfidfモデル、tfidfベクトルを作成。

#####④ tfidfベクトルとsvmを用いて、分類器を作成
tfidfベクトルとラベルを基にsvmで学習。
    
# ソースコード
#####① twitterからテキストデータの取得
データ取得は、以下の記事を参考にしてみてください。
https://qiita.com/teri/items/e10a3be38113b31c0c9a

#####② テキストデータへのラベル付け
ラベル付けは、以下の記事を参考にしてみてください。
https://qiita.com/kazuki_hayakawa/items/18b7017da9a6f73eba77

#####③ tfidfモデルを作成
名詞、形容詞の単語のみを取得

```python

def wakati_word_list_create(sentences:list, get_word_class:list) -> list:
    #複数文から、指定の品詞(GET_WORD_CLASS)を抽出した単語リスト
    sentences_word_list = []

    for sentence in sentences:
        #一文から、指定の品詞(GET_WORD_CLASS)を抽出した単語リスト
        one_sentence_word_str = ''
        #形態素解析
        node = mecab.parseToNode(sentence)

        while node:
            
            #語幹
            word = node.feature.split(",")[-3]
            #品詞
            word_class = node.feature.split(",")[0]  
            #(指定の品詞(GET_WORD_CLASS)である) and (語幹が＊のもの(つまり未知語))場合は、単語リストに追加
            if word_class in get_word_class and word != '*': 
                one_sentence_word_str = one_sentence_word_str + " " + word

            node = node.next
        sentences_word_list.append(one_sentence_word_str)
    return sentences_word_list

#twitterデータから、指定品詞の分かち分割形式の単語リストを生成
wakati_word_list = nlp_util.wakati_word_list_create(search_tweet_list, GET_WORD_CLASS)
```

tfidfモデル、tfidfベクトルを作成

```python
#tfidfベクトル化
from sklearn.feature_extraction.text import TfidfVectorizer

tfidf = TfidfVectorizer(use_idf=True, token_pattern=u'(?u)\\b\\w+\\b')
#tfidfモデルの作成
tfidf_model = tfidf.fit(wakati_word_list)
#tfidfベクトルに変換
vectors = tfidf_model.transform(wakati_word_list).toarray()
```

#####④ tfidfベクトルとsvmを用いて、分類器を作成
準備したデータを学習データ、テストデータに振り分ける。
今回は学習データを7割、テストデータを3割に振り分ける。

```python
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler 

input_train, input_test, output_train, output_test = train_test_split(vectors, targets, test_size=0.3, random_state=None )

sc = StandardScaler()
sc.fit(input_train)
input_train_std = sc.transform(input_train)
input_test_std = sc.transform(input_test)
```

tfidfベクトルとsvmで学習。

```python
from sklearn.svm import SVC
# 学習インスタンス生成
svc_model = SVC(kernel='linear', random_state=None)

# 学習
svc_model.fit(input_train_std, output_train)
```

学習データで精度確認

```python
from sklearn.metrics import accuracy_score

#traning dataのaccuracy
pred_train = svc_model.predict(input_train_std)
accuracy_train = accuracy_score(output_train, pred_train)
print('traning data accuracy： %.2f' % accuracy_train)
```
実行結果は以下。
traning data accuracy： 1.00

テストデータで精度確認

```python
#test dataのaccuracy
pred_test = svc_model.predict(input_test_std)
accuracy_test = accuracy_score(output_test, pred_test)
print('test data accuracy： %.2f' % accuracy_test)
```
実行結果は以下。
test data accuracy： 0.93


#少し遊んでみました。

適当な文章を入力して、ちゃんと分類されるか試してみました。
input_textsに格納されている文章が、「自然言語処理」、「機械学習」、「データサイエンティスト」のいずれかに分類されます。

```python
#正解ラベル{1:機械学習、2:データサイエンティスト, 3:自然言語処理}
input_texts = [
                "自然言語処理の技術発展スピードはすごいな～",
                "データサイエンティストってどんな職種なんやろかー",
                "機械学習用のデータを集めるのって大変やなー",
                "自然言語処理系のデータサイエンティストって楽しそう！！",
                "ネガポジ分析について",
                "言葉ネットワークとは？",
              ]
wakati_input_texts = nlp_util.wakati_word_list_create(input_texts, GET_WORD_CLASS)
tfidf_vectors = tfidf_model.transform(wakati_input_texts).toarray()
predict = svc_model.predict(tfidf_vectors)

print("{:　<30} : {:　<20}".format("予測する文章", "予測結果"))
print("====================================================================================")
for pre, text in zip(predict, input_texts):
    print("{:　<30} : {:　<20}".format(text, LABEL_MAP[pre]))
```

実行結果は以下。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239022/36aa3f2d-cd80-f989-9971-0ccc922a6f0e.png)

ネガポジ分析、言葉ネットワークが機械学習に分類されるのは、よくないっすね・・・。

# 考察
ネガポジ分析、言葉ネットワークは、個人的には、自然言語処理に分類してほしかったんですが、機械学習に分類されちゃいました。。。
今回は、tfidfベクトルを使ったため、学習に用いた単語以外の単語を入力されると、分類が難しいんだと思います。なので、これを解消するためには、word2vecなどの分散表現を使うことで、より色んな単語に対応させ精度が高まるかと思います。
次回は、word2vecを使った分類器を作って、精度比較をしてみますね！！


#参考にさせて頂いた記事です。
* http://ailaby.com/tfidf/
* https://qiita.com/kazuki_hayakawa/items/18b7017da9a6f73eba77