Python（ML-Ask）で口コミのポジネガ分析をする

# はじめに
本記事では、Pythonとそのライブラリで提供されているML-Askを使って、じゃらんの口コミでポジネガ分析を行います。使用するデータは前回の記事[Pythonでじゃらんの口コミをスクレイピングする][Scraping]で取得したものになります。

[Scraping]:https://qiita.com/yuya2220/items/870739cf07a61de18299

# 環境
python 3.10.4
Windows 11 Home

# ML-Askとは
感情表現辞典に登録されている2100語を元に「喜・怒・昂・哀・好・怖・安・厭・驚・恥」の10種類の感情を抽出することのできるモデルです。文章がポジティブなものか、ネガティブなものかも判定することができます。

# 使用するライブラリ
```python
pip install pymlask
pip install mecab-python3
pip install matplotlib
pip install unidic
python -m unidic download
```
# 使用例
`text`に例文を入れて実行します。

### 作成コード
```python
import MeCab
from mlask import MLAsk

emotion_analyzer = MLAsk()
text = "夕食がとても美味しく友達も喜んでいました。ありがとうございます！" \
       "客室担当方はフレンドリーで丁寧に接客してくれました。" \
       "朝ご飯もちょうどいいくらいの量で満足でした。" \
       "部屋も予想よりも広くびっくりしました。"
analyze_result = emotion_analyzer.analyze(text)
print(analyze_result)
```
- `import MeCab`
日本語形態素解析システムをインポート

MeCabをインポートしないとMLAsk()の実行に失敗するため、記入が必須です。

### 実行結果

```
{'text': '夕食がとても美味しく友達も喜んでいました。ありがとうございます！客室担当方はフレンドリーで丁寧に接客してくれました。朝ご飯もちょうどいいくらいの量で満足でした。部屋も予想よりも広くびっくりしました。', 
'emotion': defaultdict(<class 'list'>, {'odoroki': ['ビックリ'], 'suki': ['フレンドリー']}), 
'orientation': 'mostly_POSITIVE', 
'activation': 'ACTIVE', 
'emoticon': None, 
'intension': 2, 
'intensifier': {'interjections': ['んで', 'ありがとう'], 'gitaigo': ['びっくり']}, 
'representative': ('suki', ['フレンドリー'])}  
```

分析に使用できそうなのは次の2項目です。
- `emotion`
文章内で感情と判断された語句の一覧
- `orientation`
ポジネガ判定結果
項目はmostly_POSITIVE 、POSITIVE、NEUTRAL、NEGATIVE 、mostly_ NEGATIVEの5つ

# 口コミデータを使った応用
全口コミにポジネガ判定を行い、判定結果の比率を円グラフで描写します。

### 作成コード
```python
import pandas as pd
import MeCab
import matplotlib.pyplot as plt
from mlask import MLAsk

#ポジネガ判定の結果が入ったDataFrameを作成する
def make_emotion_df():
  comment_df = pd.read_csv('ホテル南風荘_口コミデータ.csv')
  emotion_analyzer = MLAsk()
  emotion_results = []
  for comment_i in comment_df['本文']:
      try:
        analyze_result = emotion_analyzer.analyze(comment_i)
        imp = analyze_result['orientation']
        emotion_results.append(imp)
      except:
        #ポジネガ判定ができなかった場合
        emotion_results.append('NONE')

  emotion_df = pd.DataFrame(emotion_results, columns=['印象区分'])
  emotion_df.index.name = 'index'
  return emotion_df

#円グラフを描写する
def make_circle(emotion_df):
  sizes = emotion_df['印象区分'].value_counts() 
  labels = emotion_df['印象区分'].value_counts().index 
  fig = plt.figure(figsize=(10, 8))
  ax = fig.add_subplot()
  ax.pie(
      sizes,
      counterclock=False, # 時計回りに比率が高い順に並び変え
      startangle=90, # 表示のアングルの調整
      autopct="%.1f%%", #小数点第一位までパーセント表示
      pctdistance=1.1, # 割合の表示位置
      radius=0.8, # 円グラフの半径
      rotatelabels=True, # ラベル表示の回転有無
  )
  ax.legend(labels, loc='upper right')
  plt.show()

emotion_df = make_emotion_df()
make_circle(emotion_df)
```
### 解説

```python:解説1
def make_emotion_df():
  comment_df = pd.read_csv('ホテル南風荘_口コミデータ.csv')
  emotion_analyzer = MLAsk()
  emotion_results = []
  for comment_i in comment_df['本文']:
      try:
        analyze_result = emotion_analyzer.analyze(comment_i)
        imp = analyze_result['orientation']
        emotion_results.append(imp)
      except:
        #ポジネガ判定ができなかった場合
        emotion_results.append('NONE')

  emotion_df = pd.DataFrame(emotion_results, columns=['印象区分'])
  return emotion_df
```
- `pd.read_csv('csvファイル名')`
csvファイルの読み込み
- `comment_df['列名']`
指定した列名が持つデータを抽出
- `pd.DataFrame(配列, columns=['列名'])`
columnsで指定した列名を持つDataFrameを作成

```python:解説2
def make_circle(emotion_df):
  sizes = emotion_df['印象区分'].value_counts() 
  labels = emotion_df['印象区分'].value_counts().index 
  fig = plt.figure(figsize=(10, 8))
  ax = fig.add_subplot()
  ax.pie(
      sizes,
      counterclock=False, # 時計回りに比率が高い順に並び変え
      startangle=90, # 表示のアングルの調整
      autopct="%.1f%%", #小数点第一位までパーセント表示
      pctdistance=1.1, # 割合の表示位置
      radius=0.8, # 円グラフの半径
      rotatelabels=True, # ラベル表示の回転有無
  )
  ax.legend(labels, loc='upper right')
  plt.show()
```
- `emotion_df['列名'].value_counts()`
重複を除いた要素の個数
- `emotion_df['列名'].value_counts().index`
重複を除いた要素の一覧
- `plt.figure(figsize=(x, y))`
横幅をx×100ピクセル、高さをy×100ピクセルの図を作成
- `ax.pie`
円グラフを作成
- `ax.legend(labels, loc='表示位置')`
凡例の表示
- `plt.show()`
グラフの描写

### 実行結果
<img width="500" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3292716/8f54e9bb-c2a5-5dff-184f-97e8c8242762.png>

2100語では判定できない文章が多く、判定できなかった場合の「NONE」が90％近くを占める結果となりました。

# 終わりに

今回はML-Askを使ってポジネガ分析を行いました。
辞書に登録された2100語ではポジティブ・ネガティブを判定できない場合が多く、ポジネガ分析には適していないと感じました。
    ですが、「喜・怒・昂・哀・好・怖・安・厭・驚・恥」の感情を検出できるのはML-Askの強みであるので、これらの感情を使って分析をしたい場合には使用するのが良さそうです。
次回はBERTを使用してポジネガ分析を行う予定です。

# 参考

この記事は以下の情報を参考にして執筆しました。
- [自然言語処理を使ったソフトウエア開発](https://nagomi-informal.net/archives/1159
)
- [【データ分析】PandasとMatplotlibで円グラフを描画する](https://zerofromlight.com/blogs/detail/96/)