3. Pythonによる自然言語処理　5-2. 感情強度分析ツール VADER

* 英語を対象とした感情値分析ツールですが、 [VADER（Valence Aware Dictionary and sEntiment Reasoner）](https://www.codeproject.com/Articles/5269445/Using-Pre-trained-VADER-Models-for-NLTK-Sentiment)は、ソーシャルメディアに適用できるようにカスタマイズされたモデルであり、NLTK パッケージで提供されています。
* 往々にしてテキストには複数の感情が含まれているものですが、VADER では**感情の両極性（ポジティブ/ネガティブ）**とともに**感情の強度**を評価し、また**否定修飾語**（"not"）とその**短縮形**（"n’t"）にも対応しています。
* また、例えば "kind of" の口語体 "kinda" や日本語で「サイテー」と言うときの "sux" といった**スラング**にも対応し、あるいは単語以外に感情強度を示すものとして**感嘆符**や**顔文字**なども認識して感情値スコアに反映されます。


#⑴ VADER感情分析ツールの用法･概要
* VADER は**「辞書」と「ルール」の組み合わせで感情値を求める**もので、学習の必要はありません。
* まず➊ VADER の辞書をダウンロードして、➋ nltk から VADER 感情値分析のクラス `SentimentIntensityAnalyzer` をインポートし、➌インスタンスを生成するという３ステップです。

```python
import nltk

# ➊辞書のダウンロード
nltk.download('vader_lexicon')
# ➋感情強度分析クラスのインポート
from nltk.sentiment.vader import SentimentIntensityAnalyzer

# ➌インスタンスの生成
vader_analyzer = SentimentIntensityAnalyzer()
```
* VADER の辞書 [vader_lexicon.txt](https://github.com/cjhutto/vaderSentiment/blob/master/vaderSentiment/vader_lexicon.txt) には 7,520 語が登録されています。
* さまざまな言語資源から語彙を収集し、人手により positive/negative の度合い [-4, +4] を評定した上で、文脈によってネガポジが変わりやすい語などをふるい落した成果物となっています。
* つまり辞書は、語彙の positive/negative の程度を意味論的に規定したもので、言い換えれば、単語にネガポジの色合いの濃淡を付与したものに過ぎません。
* そこで、感情的な強度を示すものとして、感嘆符 ! とその数、語を全て大文字で書く強調表現、程度を意味する副詞（eg. "partly" =いくらか, "extreamy" =非常に）などを採用し、また "but" の後は極性を反転させるといった**ルールによって値を補正**します。



#⑵ 感情極性の出力形式
* インスタンス `vader_analyzer` に対し、メソッド [`polarity_scores()`](https://www.kite.com/python/docs/nltk.sentiment.SentimentIntensityAnalyzer.polarity_scores) は、入力されたテキストにもとづいて感情強度を dict 型で返します。正の値はポジティブ、負の値はネガティブです。

```python
text = "I am happy."

result = vader_analyzer.polarity_scores(text)
print(text + "\n", result)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/83d70c0c-0dd4-24cc-7574-63e310638f4c.png)

* ネガティブ 'neg'、ニュートラル 'neu'、ポジティブ 'pos' の各スコアは、 "I am happy." という文章がそれぞれのカテゴリに該当する割合を表しています。つまり、ポジティブ78.7％、ニュートラル21.3％、ネガティブ0％と判定されており、3カテゴリのスコアの合計は 1 になります。
* 複合スコア 'compound' は、すべての単語のスコアの合計を [-1, +1] の間で正規化した値です。



#⑶ 感情極性のスコアリング
* ごく単純な感情表現として、先の "I am happy." のほか、"I am sad." と "I am angry." を対象に判定結果を見てみます。

```python
import pandas as pd

sentences = ["I am happy.", "I am sad.", "I am angry."]

# スコアを取得
result = []
for s in sentences:
    score = vader_analyzer.polarity_scores(s)
    result.append(score)

# 辞書型からデータフレームに変換
i = 0
df = pd.DataFrame()
for i in range(3):
    x = pd.DataFrame.from_dict(result[i], orient='index').T
    df = pd.concat([df,x], ignore_index=True)
df.index = sentences

print(df)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/13d3de11-f42e-fa2b-da57-a6e222ff5b67.png)

* "I am sad." と "I am angry." が共にネガティブなのは明白ですが、内向的な「悲しい」よりも「腹が立つ」の方がより積極的な感情の在り方としてネガティブの度合いが高く判定されています。
* もう一つ、日本語で「それは素晴らしい」の英語対訳はいくつかありますが･･･

```python
sentences = ["That's fantastic.", "That's wonderful.", "That's great."]
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/28decf88-db6c-14de-bbde-1eadaf52afdb.png)

* 微妙な温度差の違いが見て取れますが、なるほど "fantastic" や "wonderful" がやや第三者的な感じがあるのに対して、いっそ "great" と言った方が当事者的な熱気が感じられないでしょうか。

#⑷ 否定形･短縮形 及び複合文
* 否定形の "not" とその短縮形 "n't" 、及び一文中に背反する意味がある場合の判定のしかたを見てみます。

```python
sentences = ["I was not happy.", "I wasn't happy.", "I'm rich but unhappy."]

result = []
for s in sentences:
    score = vader_analyzer.polarity_scores(s)
    result.append(score)

i = 0
df = pd.DataFrame()
for i in range(3):
    x = pd.DataFrame.from_dict(result[i], orient='index').T
    df = pd.concat([df,x], ignore_index=True)
df.index = sentences

print(df)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/8115fe49-1769-d0a3-ba7b-fa42300d2253.png)

* "I was not happy." と "I wasn't happy." は「私は幸せではなかった」という意味において全く同一であり、複合スコアも一致しています。ただし、3カテゴリの割合を見ると、短縮形 "I wasn't happy." の方がネガティブの割合が高くなっています。察するに、"I was not happy." より "I wasn't happy." の方が多くは口語的でその分ストレートな感じを受けますし、それだけに感情強度はやや強めということでしょうか。
* また、"I'm rich but unhappy." すなわち「金持ちだが不幸だ」というのですが、"rich" というポジティブな側面はあるけれども "but" で感情極性は負に転じて "unhappy" とネガティブに結論づけています。スコアもまたネガティブの割合が最も高く、ポジティブは打ち消されて、複合スコアはネガティブとなっています。


#⑸ 感嘆符･大文字による強度表現
* 思いの丈を表す直接的かつ慣用的なスタイルです。感嘆符 ! とその数、及び全て大文字で書かれた語、これらが感情強度としてどのように判定されるかを見てみます。

```python
sentences = ["I am happy.", "I am happy!", "I am happy!!", "I am happy!!!", "I am HAPPY."]

result = []
for s in sentences:
    score = vader_analyzer.polarity_scores(s)
    result.append(score)

i = 0
df = pd.DataFrame()
for i in range(5):
    x = pd.DataFrame.from_dict(result[i], orient='index').T
    df = pd.concat([df,x], ignore_index=True)
df.index = sentences

print(df)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/bffcc226-ba2c-34c1-0390-09f42e111068.png)

* 感嘆符 ! の数が増えるほどポジティブな感情強度は高まり、複合スコアも高くなっていますが、試しに可視化してみましょう。

```python
import matplotlib.pyplot as plt
from matplotlib import pyplot as pyplot

x = (df.index.values.tolist())[0:4]
y = df.iloc[0:4, 3]
plt.plot(x, y, marker="o")

plt.axhline(y=df.iloc[4, 3], color='r', linestyle='-')

plt.ylabel("compound score")
plt.legend(['number of "!"','uppercase notation'])
plt.grid()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/19adfceb-46fa-939a-5df9-288a35e1c7fa.png)

* 赤い水平線で "HAPPY" と大文字で書いた場合のスコアを示していますが、!! と !!! の中間レベルとなっています。となると、"It's great!!" < "It's GREAT." < "It's great!!!" という図式も考えられそうですが、日本語に置き換えると「凄いですね!!」 < 「それは素晴らしい」 < 「凄いですね!!!」という感じでしょうか。


#⑹ 顔文字による感情表現
* 顔文字のことを欧米では「emoticon」(emotion+icon) などと称し、日本のそれとはかなり様子が異なります。
* 日本では正面顔で主に目で感情表現をするのに対し、欧米では、顔を左に90°傾けて、主に口にあたる部分で感情表現をしています。例えば、笑顔は「:-)」「:)」、驚きは「:-o」「:O」、悲しみ・涙は「:-(」「:(」という具合です。
* 欧米式はいささか記号的な感じで、日本式の方が絵画的で表現力が豊かだと感じるのは私だけでしょうか。

```python
sentences = ["I love you.", "I love you :-*","I love you <3"]

result = []
for s in sentences:
    score = vader_analyzer.polarity_scores(s)
    result.append(score)

i = 0
df = pd.DataFrame()
for i in range(3):
    x = pd.DataFrame.from_dict(result[i], orient='index').T
    df = pd.concat([df,x], ignore_index=True)
df.index = sentences

print(df)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/c7fa502d-4b6a-2ea3-a68c-227f0681050a.png)

* ポジティブの感情強度が最も高い "I love you <3" の「<3」はハートマークを表しますが、数字の3を使う都合上 右に90°傾いています。また "I love you :-*" の方は顔文字で「キス」を意味します。
* 次いで、笑顔を表す顔文字を使った場合の感情強度を見てみます。

```python
sentences = ["I am happy.", "I am happy :-)", "I am happy (^^)"]
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502109/7998b3df-afe8-a345-5ad5-cff9cea91207.png)

* 「:-)」が入るとポジティブの感情強度はかなり高まります。対して日本式の顔文字をつかった場合は、ポジティブの強度が低めにふれていますが、複合スコアでみると単なる "I am happy." と変わりません。

---
* 以上のように、SNS の英語テキストを容易に分析することができて、判定結果もほぼ頷けるものとなっており、かなり実用に値するものとなっています。
* 次に、日本語の感情値分析を見ていきたいと思います。