はじめに
センチメント分析とは、テキストを分析して、肯定的・否定的・中立的かを判断することです。
今回は、一般に公開されているモデルを使ってセンチメント分析してみたので、メモ書き程度に手順を書いていこうと思います。
一部AIを使って文章を出力しているので、内容の妥当性は保証しかねます。
使用する環境
- python 3.12.3
- Jupyter Notebook上で実行
使用するモデル
- asari
- BERT日本語モデル
-
Hugging Face に公開されているモデル
- christian-phu/bert-finetuned-japanese-sentiment
- koheiduck/bert-japanese-finetuned-sentiment
- Mizuiro-sakura/luke-japanese-large-sentiment-analysis-wrime
分析する文章 (sample.txt)
各モデルの比較のため、分析する文章をsample.txtとして用意しました。
友達と過ごした時間が本当に楽しかった。
彼の無礼な態度には本当に腹が立った。
新しいプロジェクトが始まるのが待ち遠しい。
彼の話を聞いて、心がとても痛んだ。
発表中に間違えてしまい、顔が赤くなった。
各センチメント分析の実行
asari
asari
- Asari は Python で実装された日本語感情分析ツール
- 文章を tf-idf (term frequency–inverse document frequency) でベクトル表現に変換し、
それを線形カーネルのサポートベクトルマシンを使って分類問題として文章が肯定的か否定的かを判定する - どのトレーニングデータセットを使って学習したかが不明なので、どんな種類の文章で適切に判定できるかが不明
asariのインストール
-q
は出力メッセージを抑止(quiet)するオプションです。
! pip install -q asari
ソースコード
from asari.api import Sonar
sonar = Sonar()
# sample.txtファイルを一行ずつ読み込む
with open('sample.txt', 'r', encoding='utf-8') as file:
lines = file.readlines()
# 各行に対して感情分析を実行
for line in lines:
text = line.strip()
if text: # 空行を無視
print('*' * 50)
result = sonar.ping(text=text)
# 出力結果の表示
for key, value in result.items():
if key=='classes':
for item in value:
print(f"{item['class_name']}: {item['confidence']}")
else:
print(f"{value}")
結果
「腹が立った」や「心が痛んだ」のにpositiveの値が高く、想定した値とは離れてしまいました。
asari
は私がやりたいことには向いていなかったようです。
**************************************************
友達と過ごした時間が本当に楽しかった。
positive
negative: 0.05891948938369751
positive: 0.9410804510116577
**************************************************
彼の無礼な態度には本当に腹が立った。
positive
negative: 0.32674068212509155
positive: 0.6732593178749084
**************************************************
新しいプロジェクトが始まるのが待ち遠しい。
positive
negative: 0.06825879961252213
positive: 0.9317412376403809
**************************************************
彼の話を聞いて、心がとても痛んだ。
positive
negative: 0.0010003686184063554
positive: 0.9989995956420898
**************************************************
発表中に間違えてしまい、顔が赤くなった。
negative
negative: 0.7915144562721252
positive: 0.20848560333251953
christian-phu/bert-finetuned-japanese-sentiment
christian-phu/bert-finetuned-japanese-sentiment
ライブラリのインストール
! pip install -q transformers
! pip install -q torch
ソースコード
import torch
from transformers import pipeline, AutoModelForSequenceClassification, AutoTokenizer
# 事前学習済みの日本語感情分析モデルとそのトークナイザをロード
model = AutoModelForSequenceClassification.from_pretrained('christian-phu/bert-finetuned-japanese-sentiment')
tokenizer = AutoTokenizer.from_pretrained('christian-phu/bert-finetuned-japanese-sentiment', model_max_length=512)
# 感情分析のためのパイプラインを設定
nlp = pipeline('sentiment-analysis', model=model, tokenizer=tokenizer, truncation=True)
# sample.txtファイルを一行ずつ読み込む
with open('sample1.txt', 'r', encoding='utf-8') as file:
lines = file.readlines()
# 各行に対して感情分析を実行
for line in lines:
text = line.strip()
if text: # 空行を無視
print('*' * 50)
inputs = tokenizer(text, padding=True, truncation=True, return_tensors='pt', max_length=512)
outputs = model(**inputs)
logits = outputs.logits
# ロジットを確率に変換
probabilities = torch.softmax(logits, dim=1)[0]
# 最も高い確率の感情ラベルを取得
sentiment_label = model.config.id2label[torch.argmax(probabilities).item()]
# 出力結果の形式に合わせて表示
print('テキスト:{}'.format(text))
print('感情:{}'.format(sentiment_label))
print('クラス:')
print(' negative: {:.6f}'.format(probabilities[0].item()))
print(' neutral: {:.6f}'.format(probabilities[1].item()))
print(' positive: {:.6f}'.format(probabilities[2].item()))
結果
恥ずかしい感情は難しかったでしょうか。
「発表中に間違えてしまい、顔が赤くなった」がほぼ中立的な感情となってしまっています。
それ以外の分析結果は異論なしですね。
**************************************************
テキスト:友達と過ごした時間が本当に楽しかった。
感情:positive
クラス:
negative: 0.001431
neutral: 0.000381
positive: 0.998188
**************************************************
テキスト:彼の無礼な態度には本当に腹が立った。
感情:negative
クラス:
negative: 0.914916
neutral: 0.032695
positive: 0.052389
**************************************************
テキスト:新しいプロジェクトが始まるのが待ち遠しい。
感情:neutral
クラス:
negative: 0.000997
neutral: 0.994601
positive: 0.004403
**************************************************
テキスト:彼の話を聞いて、心がとても痛んだ。
感情:negative
クラス:
negative: 0.933600
neutral: 0.021949
positive: 0.044451
**************************************************
テキスト:発表中に間違えてしまい、顔が赤くなった。
感情:negative
クラス:
negative: 0.494469
neutral: 0.425086
positive: 0.080445
koheiduck/bert-japanese-finetuned-sentiment
koheiduck/bert-japanese-finetuned-sentiment
ソースコード
from transformers import BertJapaneseTokenizer
from transformers import AutoModelForSequenceClassification
from transformers import pipeline
# パイプラインの準備
model = AutoModelForSequenceClassification.from_pretrained('koheiduck/bert-japanese-finetuned-sentiment')
tokenizer = BertJapaneseTokenizer.from_pretrained('koheiduck/bert-japanese-finetuned-sentiment')
nlp = pipeline("sentiment-analysis", model=model, tokenizer=tokenizer)
# sample.txtファイルを一行ずつ読み込む
with open('sample1.txt', 'r', encoding='utf-8') as file:
lines = file.readlines()
# 各行に対して感情分析を実行
for line in lines:
text = line.strip()
if text: # 空行を無視
print(text)
print(nlp(text))
print()
結果
Hugging Face で一番ダウンロード数が多かったのはこの精度の良さのためでしょうか。
一番分析結果がしっくりきます。
友達と過ごした時間が本当に楽しかった。
[{'label': 'POSITIVE', 'score': 0.992745041847229}]
彼の無礼な態度には本当に腹が立った。
[{'label': 'NEGATIVE', 'score': 0.9904448390007019}]
新しいプロジェクトが始まるのが待ち遠しい。
[{'label': 'POSITIVE', 'score': 0.8975418210029602}]
彼の話を聞いて、心がとても痛んだ。
[{'label': 'NEGATIVE', 'score': 0.9931499361991882}]
発表中に間違えてしまい、顔が赤くなった。
[{'label': 'NEGATIVE', 'score': 0.9449061155319214}]
Mizuiro-sakura/luke-japanese-large-sentiment-analysis-wrime
Mizuiro-sakura/luke-japanese-large-sentiment-analysis-wrime
こちらは、前述したモデルと少し異なり、肯定的・否定的だけではなく、
8つの感情(喜び、悲しみ、期待、驚き、怒り、恐れ、嫌悪、信頼)を分析してくれるみたいです。おもしろそうなので試してみます。
ソースコード
from transformers import AutoTokenizer, AutoModelForSequenceClassification, LukeConfig
import torch
tokenizer = AutoTokenizer.from_pretrained("Mizuiro-sakura/luke-japanese-large-sentiment-analysis-wrime")
config = LukeConfig.from_pretrained('Mizuiro-sakura/luke-japanese-large-sentiment-analysis-wrime', output_hidden_states=True)
model = AutoModelForSequenceClassification.from_pretrained('Mizuiro-sakura/luke-japanese-large-sentiment-analysis-wrime', config=config)
with open('sample1.txt', 'r', encoding='utf-8') as file:
lines = file.readlines()
for text in lines:
max_seq_length=512
token=tokenizer(text,
truncation=True,
max_length=max_seq_length,
padding="max_length")
output=model(torch.tensor(token['input_ids']).unsqueeze(0), torch.tensor(token['attention_mask']).unsqueeze(0))
max_index=torch.argmax(torch.tensor(output.logits))
print(text)
if max_index==0:
print('joy、うれしい')
elif max_index==1:
print('sadness、悲しい')
elif max_index==2:
print('anticipation、期待')
elif max_index==3:
print('surprise、驚き')
elif max_index==4:
print('anger、怒り')
elif max_index==5:
print('fear、恐れ')
elif max_index==6:
print('disgust、嫌悪')
elif max_index==7:
print('trust、信頼')
print()
結果
これはこれで面白いですね。精度も悪くなさそうです。
分類する感情に「恥ずかしい」などもあったらよいのでしょうか。人の感情って何種類あるんでしょうね。
そういえば、頭の中に「感情」がいる映画もあったような…。
友達と過ごした時間が本当に楽しかった。
joy、うれしい
彼の無礼な態度には本当に腹が立った。
anger、怒り
新しいプロジェクトが始まるのが待ち遠しい。
anticipation、期待
彼の話を聞いて、心がとても痛んだ。
sadness、悲しい
発表中に間違えてしまい、顔が赤くなった。
fear、恐れ
おわりに
koheiduck/bert-japanese-finetuned-sentiment
というモデルが試した中では一番しっくりきました。
余談ですが、この世には皮肉分析モデル(kit-nlp/bert-base-japanese-sentiment-irony)なるもののあるようです。気になった方は試してみてください。
よいAIライフを!