感情分析に用いる極性辞書を自動生成する

#はじめに
「自然言語処理 Advent Calendar 2019」の7日目です。
以前投稿した「[感情分析でニュース記事のネガポジ度合いをスコア化する](https://qiita.com/g-k/items/e49f68d7e2fed6e300ea)」の記事内で課題に感じた、**「使える極性辞書あんまりない問題」**の解決を試みました。今回はfasttextを用いて極性辞書の自動生成に挑みます。

#参考
fasttextの学習の際に下記を参考にさせていただきました。

- [fastTextで自然言語(日本語)の学習モデルを生成する手順まとめ](https://dot-blog.jp/news/fasttext-natural-language-machine-learning-tutorial/)　
- [fastTextの学習済みモデルを公開しました](https://qiita.com/Hironsan/items/513b9f93752ecee9e670)　

#感情分析とは何か
##感情分析概要
感情分析とは様々なテキスト情報をテキストマイニングや機械学習の技術を用いて、その**記述内容の感情を分析する手法**です。ポジティブorネガティブの1軸の分析が最もオーソドックスな印象ですが、より細かい感情の分析に踏み込んでいるものもあります。

##感情分析の方法
感情分析において最も一般的なのは**文章に含まれる単語に着目する方法**で、ポジティブ（ネガティブ）な文面にはそれ特有の単語が含まれるはずという考えに基づいています。そのような特定の単語を集めたリストを**極性辞書**と呼び、今回の感情分析ではこの極性辞書を用います。

##極性辞書
###極性辞書について
極性辞書とは、**単語や用語毎に「ポジティブ」「ネガティブ」といった意味上のフラグ立てがなされた辞書**のことを言います。単に「ポジティブ」「ネガティブ」といったフラグだけのものもあればポジティブ度合いやネガティブ度合いが離散的なスコア数値として与えられているものもあります。

##感情分析における課題

###便利に使える極性辞書が殆どない
感情分析をしたいと考えて色々と極性辞書を探したのですが、実際に使用できそうな極性辞書は下記の二つくらいしかありませんでした。[単語感情極性対応表](http://www.lr.pi.titech.ac.jp/~takamura/pndic_ja.html)には大量の単語に対してネガポジの離散的な値(-1から1の範囲で)が付与されていて非常に便利なのですが、商用での利用が不可になっています。

- [単語感情極性対応表](http://www.lr.pi.titech.ac.jp/~takamura/pndic_ja.html)　
- [日本語評価極性辞書](https://www.cl.ecei.tohoku.ac.jp/index.php?Open%20Resources%2FJapanese%20Sentiment%20Polarity%20Dictionary)　

###チューニングが非常に面倒
実際、各単語にネガポジ度合いの値を割り振ると言っても**その分析する対象や文脈、ネガポジ反転を行う観点によってはその単語がポジティブと判定されるべきなのかネガティブと反映されるべきなのかは異なります。**よって、本来であればタスクに応じて極性辞書は丸ごとチューニングされるべきなのですが、それをやろうとすると非常に時間がかかってしまいます。

##上記課題の解決
###fasttextを用いた極性辞書の自動生成
上記課題の解決として**極性辞書を簡易的に自動生成でき、かつチューニングも容易なプログラムを作成したいと思います。**

#極性辞書の自動生成
##自動生成プログラムの概要
下記のような仕組みの極性辞書自動生成プログラムを作成してみました。

1. ネガポジ判定したい文書群における**「非常にポジティブな単語」**と**「非常にネガティブな単語」**を複数個ずつ指定
2. wikipedia日本語ページを全量学習したfasttextのモデルを用い、各文章内の形態素に対して上記の**「非常にポジティブな単語」**たちとの類似度平均と**「非常にネガティブな単語」**たちとの類似度平均を測る。
3. 類似度平均が高い方の極性を採用します。「ポジティブ」の方ならば類似度を値をそのまま、「ネガティブ」であればマイナスを付与して、その形態素のネガポジスコアとします。
4. 全単語のスコアのスケールを-1から1に変換して極性辞書が完成です。

##極性辞書自動生成プログラムの実装
###fasttextについて
今回単語間の類似度を測るためにfasttextを用いています。Word2vecとの比較も行なったのですがfasttextの方がどうも反意語に強いようなので、fasttextの方を採用いたしました。
fasttextのモデルについて、私は一から作成したのですが学習に300時間も掛かってしまいました...
学習済みモデルを公開してくださっている方いらっしゃるので([fastTextの学習済みモデルを公開しました](https://qiita.com/Hironsan/items/513b9f93752ecee9e670)など　
)ので基本的にはそちらの利用で問題ないかと思います。
[参考](https://drive.google.com/file/d/1GI6BIlg8qGCMm0Gwij1L5paDYUl0VKfA/view?usp=sharing)

また丁度Advent Calendarにてfasttextについて書いてくださっている方がいらっしゃるので是非ご覧ください。
[fastTextでサクッと単語の分散表現を使ってみよう！](https://qiita.com/MonaCat/items/c26fa660a711f010c39a)

###ネガポジ度合いの自動判定
まず、特定の単語のネガポジ度合いを判定するプログラムを作成します。

```python
import gensim
#fasttextのモデルを読み込む
model = gensim.models.KeyedVectors.load_word2vec_format('./wikimodel_20191102.bin', binary=True)

#「非常にポジティブな単語」と「非常にネガティブな単語」を任意で指定
posi_list = ['優れる', '良い','喜ぶ','褒める', 'めでたい','賢い','善い', '適す','天晴',
 '祝う', '功績','賞','嬉しい','喜び','才知','徳', '才能','素晴らしい','芳しい','称える',
 '適切','崇める','助ける','抜きんでる','清水','雄雄しい','仕合せ','幸い','吉兆','秀でる']

nega_list = ['悪い', '死ぬ', '病気', '酷い', '罵る', '浸ける', '卑しい',
 '下手', '苦しむ', '苦しい', '付く', '厳しい', '難しい', '殺す', '難い', '荒荒しい',
 '惨い', '責める', '敵', '背く', '嘲る', '苦しめる', '辛い', '物寂しい', '罰', '不貞腐る',
 '寒い', '下らない', '残念']

def posi_nega_score(x):
    #ポジティブ度合いの判定
    posi = []
    for i in posi_list:
        try:
            n = model.similarity(i, x)
            posi.append(n)
        except:
            continue
    try:
        posi_mean = sum(posi)/len(posi)
    except:
        posi_mean = 0

    #ネガティブ度合いの判定
    nega = []
    for i in nega_list:
        try:
            n = model.similarity(i, x)
            nega.append(n)
        except:
            continue
    try:
        nega_mean = sum(nega)/len(nega)
    except:
        nega_mean = 0
    if posi_mean > nega_mean:
        return posi_mean
    if nega_mean > posi_mean:
        return -nega_mean
    else:
        return 0

```

上記プログラムを用いて単語のネガポジ判定をするとこのような感じになります。

```python
print(posi_nega_score('優秀'))
```
```
0.2679512406197878
```
```python
print(posi_nega_score('いや'))
```
```
-0.2425743742631032
```

###極性辞書自動生成プログラム
今回データセットは[「livedoor ニュースコーパス」](https://www.rondhuit.com/download.html#ldcc)を使用させていただきます。データセットの詳細やその形態素解析の方法は[以前投稿した記事で投稿](https://qiita.com/g-k/items/e49f68d7e2fed6e300ea)しているの気になる方そちらをご参照いただければと思います。形態素解析した結果はこのような感じで出力しています。

![スクリーンショット 2019-12-07 8.51.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395230/cea9ba1f-2e13-70e9-5756-9411dd4022d2.png)

こちらのデータを元に極性辞書を生成します。

```python

import pandas as pd
ddf = pd.read_csv('news_word.csv')

#各単語にスコアを割り振る
ddf['スコア'] = ddf['単語'].apply(lambda x : posi_nega_score(x))

import numpy as np
#与えられたスコアを-1から1の範囲に調整
score = np.array(ddf['スコア'])
score_std = (score - score.min())/(score.max() - score.min())
score_scaled = score_std * (1 - (-1)) + (-1)
ddf['スコア'] = score_scaled
```
上記プログラムで作成した極性辞書の**ネガティブ単語トップ20**はこちら。

![スクリーンショット 2019-12-07 8.58.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395230/1fe490c8-1fe8-955b-b955-8d2700fb92a0.png)

上記プログラムで作成した極性辞書の**ポジティブ単語トップ20**はこちら。

![スクリーンショット 2019-12-07 9.00.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395230/c3b28d14-be32-d1c6-328d-1a4e68cc1cf6.png)

ちゃんとそれっぽい単語が入ってきていることがわかります。ネガティブ単語やポジティブ単語として指定しなかったワードも入ってきているので、割と精度は良いのではないかなと思っています。

#Next
最後までご覧いただきありがとうございました。
「Advent Calendar」は初参戦でしたがこれからも積極的に参加していきたいと思います。
明日は[oumugai mori](https://qiita.com/oumugai)さんです！！