ジャンプ漫画の名言はどんな印象？BERTでポジネガ分析をする

# はじめに
本記事ではPythonとBERTを使って、ジャンプ漫画の名言約300個のポジネガ分析を行います。[漫画名言.Net][jamp]さんのリストをお借りし、事前に「タイトル」、「キャラ」、「セリフ」の3つのカラムを持つデータを作成し、使用しています。

[jamp]:https://漫画名言.net/shuppansha/shueisha/shonenjump.html

# 環境
python 3.10.4
Windows 11 Home

# BERTとは
「Bidirectional Encoder Representations from Transformers」の略称で、2018年10月にGoogle社が発表したディープラーニングによる自然言語処理モデルです。
事前学習されたモデルと形態素解析を行うトークナイザを使って、様々な判定をすることができます。

# 使用するモデルとトークナイザ
モデルは`koheiduck/bert-japanese-finetuned-sentiment`を、トークナイザは`cl-tohoku/bert-base-japanese-whole-word-masking`を使用します。
ポジネガ分析を行っている記事の多くはモデルに`daigo/bert-base-japanese-sentiment`を使用していますが、現在(2023年8月)では公開が停止されているため、代わりに`koheiduck/bert-japanese-finetuned-sentiment`を使用しています。

# 使用するライブラリ
```python
pip install torch torchvision
pip install transformers[ja]
pip install ipadic
pip install numpy
pip install matplotlib
```
# 一文での使用例
`text`に悟空のセリフを入れて実行します。

### 作成コード
```python
import pandas as pd
from transformers import pipeline, AutoModelForSequenceClassification, BertJapaneseTokenizer

# パイプラインの準備
model = AutoModelForSequenceClassification.from_pretrained('koheiduck/bert-japanese-finetuned-sentiment') 
tokenizer = BertJapaneseTokenizer.from_pretrained('cl-tohoku/bert-base-japanese-whole-word-masking')
nlp = pipeline("sentiment-analysis",model=model,tokenizer=tokenizer)

text = "もうとっくにご存じなんだろ?オレは、地球からきさまを倒すためにやってきたサイヤ人……" \
       "穏やかな心を持ちながら激しい怒りによって目覚めた伝説の戦士…超サイヤ人孫悟空だ!!!!!" \

result = nlp(text)
print(result)
```
引用［1］


### 実行結果
```
[{'label': 'POSITIVE', 'score': 0.9241851568222046}]
```
- `label`
ポジネガ判定結果
項目はPOSITIVE、NEUTRAL、NEGATIVEの3つ
- `score`
判定の確信度

ポジティブである可能性がかなり高い文章と判定されました。「穏やかな心を持ちながら」といった部分が判定結果に影響を与えていそうです。

# 300個を使った分析
## 名言データに判定結果を追加する
名言データにポジネガ判定の結果を追加した、新しいデータを作成します。

### 作成コード
```python
import pandas as pd
from transformers import pipeline, AutoModelForSequenceClassification, BertJapaneseTokenizer

model = AutoModelForSequenceClassification.from_pretrained('koheiduck/bert-japanese-finetuned-sentiment') 
tokenizer = BertJapaneseTokenizer.from_pretrained('cl-tohoku/bert-base-japanese-whole-word-masking')
nlp = pipeline("sentiment-analysis",model=model,tokenizer=tokenizer)

input_df = pd.read_csv('名言.csv')
results = []
for row_i in input_df.itertuples():
    #row_i[1]：タイトル、row_i[2]：キャラ、row_i[3]：セリフ
    analyze_result = nlp(row_i[3])
    judge = analyze_result[0]['label']
    score = analyze_result[0]['score']
    results.append([row_i[1], row_i[2], row_i[3], judge, score])

colmn_name = ['タイトル','キャラ','セリフ','ポジネガ判定結果','確信度']
result_df = pd.DataFrame(results, columns=colmn_name)
result_df.to_csv("ポジネガ判定結果.csv", index=False, encoding="utf-8")
```
- `df.itertuples()`
1行ずつデータを取得

## 確信度の高さトップ5を出す
作成した「ポジネガ判定結果.csv」を使ってポジティブ、ネガティブそれぞれ確信度の高さトップ5を出します。

### 作成コード
```python
import pandas as pd

input_df = pd.read_csv('ポジネガ判定結果.csv')
#NEGATIVEを出す場合はNEGATIVEに変える
result_df = input_df[input_df['ポジネガ判定結果'] == 'POSITIVE'].sort_values('確信度', ascending=False)
print(result_df.head())

```

### ポジティブのトップ5

| タイトル | キャラ | セリフ | ポジネガ判定結果 | 確信度 |
| ---- | ---- | ---- | ---- | ---- |
| 僕のヒーローアカデミア | 出久の母 | 出久！超カッコイイよ | POSITIVE | 0.992608 |
| ROOKIES | 御子柴 徹 | 叶う！努力したら絶対夢は叶うんだ!! | POSITIVE | 0.989321 |
| 銀魂 | 神楽 | ケツ拭く紙は忘れたけどもっと素敵な紙は手に入れたヨ | POSITIVE | 0.987851 |
| DEATH NOTE | リューク | デスノートを使った人間が天国や地獄にいけると思うな。死んでからのお楽しみだ。 | POSITIVE | 0.987311 |
| アイシールド21 | 小早川瀬那 | 理想とは違っちゃったけど 今のがもっと楽しいそういうことだってあるよ！ | POSITIVE | 0.985723 |

上から引用［2］、［3］、［4］、［5］、［6］

おおよそポジティブに感じるセリフが並びました。リュークのセリフはネガティブ寄りに感じますが、ポジティブの可能性がかなり高い文章として判定されています。「お楽しみだ」の部分が大きな影響を与えていそうです。

### ネガティブのトップ5

| タイトル | キャラ | セリフ | ポジネガ判定結果 | 確信度 |
| ---- | ---- | ---- | ---- | ---- |
| NARUTO | 秋道チョウジ | ボクの親友を馬鹿にすることはどんな高級な料理の最後のひと口を横取りされることよりデブってバカにされることより許せない | NEGATIVE | 0.993450 |
| 暗殺教室 | 茅野 カエデ | ダメだ―――――っ!!!!愛情込めて作ったプリンを爆破なんてダメだ―――!! | NEGATIVE | 0.990961 |
| ワールドトリガー | 空閑 遊真 | つまんないウソつくねオマエ | NEGATIVE | 0.990619 |
| ROOKIES | 新庄 慶 | たばこ拾え俺たちのグラウンド汚すんじゃねーよ | NEGATIVE | 0.990419 |
| NARUTO | はたけカカシ | 忍びの世界でルールや掟を守れないやつはクズ呼ばわりされる。けどな仲間を大切にしない奴はそれ以上のクズだ。  | NEGATIVE | 0.988570 |


上から引用［7］、［8］、［9］、［10］、［11］

ネガティブと言われれば、そう感じるようなセリフが並びました。「バカ」、「クズ」等、他者を蔑むようなマイナスワードが入っていたり、「～するな」といった否定の文章になっていたりすると、ネガティブの可能性が高い文章として判定されそうです。

## 全体の比率を出す
作成した「ポジネガ判定結果.csv」を使って、全体のポジティブ、ニュートラル、ネガティブの比率を円グラフで出力します。

```python
import pandas as pd
import matplotlib.pyplot as plt

input_df = pd.read_csv('ポジネガ判定結果.csv')
sizes = input_df['ポジネガ判定結果'].value_counts() # まとまったカテゴリーの要素
labels = input_df['ポジネガ判定結果'].value_counts().index # カテゴリーネーム
colorlist = ['#A6E39D', '#ECACB5', '#AEC1E3'] #グラフ色の設定[ポジティブ,ネガティブ,ニュートラル]

fig = plt.figure(figsize=(10, 8)) # グラフ自体のサイズ（幅、高さ）
ax = fig.add_subplot()
ax.pie(
sizes,
colors=colorlist,
counterclock=False, # 時計回りに比率が高い順の設定
startangle=90, # 表示のアングルを調整
autopct="%.1f%%", #小数点以下 1 桁まで出力
pctdistance=1.1, # 割合の表示位置調整
radius=1.0, # 円グラフの半径設定
rotatelabels=True, # ラベル表示の回転有無
)
ax.legend(labels, loc='lower right') #凡例の位置の設定
plt.show()
```



### 実行結果
<img width="500" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3292716/a03145e6-6ff7-18ee-1f51-351771936614.png>

ポジティブが最も多かったですが、ネガティブもそれに迫る割合となりました。人を感動させたり、鼓舞するものが名言になるイメージだったので、ネガティブがここまで多いのは意外でした。セリフのような短い文章だと、「バカ」、「ダメ」等のマイナスワード1つで、ネガティブ判定になりがちだったので、口コミ等の長い文章であればもっと精度が上がりそうと感じました。

# 終わりに

今回はジャンプ漫画の名言を使ってポジネガ分析を行いました。
前回の[ML-ASKを使った分析][MLASK]よりも判定できる範囲が広く、ポジティブ、ネガティブの分類分けをするならBERTの方が良いと感じました。
次回はポジネガ分析を用いた、テキストマイニングを行う予定です。

[MLASK]:https://qiita.com/yuya2220/items/bed14a5e8bdddc61259e


# 引用
［1］作品：ドラゴンボール、著者：鳥山明
［2］作品：僕のヒーローアカデミア、著者：堀越耕平
［3］、［10］作品：ROOKIES、著者：森田まさのり
［4］作品：銀魂、著者：空知英秋
［5］作品：DEATH NOTE、著者：大場つぐみ、小畑健
［6］作品：アイシールド21、著者：稲垣理一郎
［7］、［11］作品：NARUTO、著者：岸本斉史
［8］作品：暗殺教室、著者：松井優征
［9］作品：ワールドトリガー、著者：葦原大介

# 参考
https://resanaplaza.com/2022/06/12/【実践】pythonとbertで感情分析しようよ！/?amp=1