0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VALTES Advent Calendar 2024

Day 10

AIを使ってセンチメント分析(感情分析)してみた

Last updated at Posted at 2024-12-24

はじめに

センチメント分析とは、テキストを分析して、肯定的・否定的・中立的かを判断することです。
今回は、一般に公開されているモデルを使ってセンチメント分析してみたので、メモ書き程度に手順を書いていこうと思います。

一部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ライフを!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?