いつのまにか Amazon Comprehend の感情分析が日本語に対応しているのを見つけたので試してみました。
Amazon Comprehend というのは AWSが提供している自然言語処理の機械学習サービスです。
すでに学習済みのモデルが用意されており、利用者はデータを渡すだけで、感情分析(ポジネガ)や、キーフレーズの抽出ができます。
少し前までは日本語は言語判別のみ対応していて、センチメント分析するには一度対応してる言語に翻訳する必要があったはずなのですが、今は日本語も使えます。
ということで、Pythonからこれを動かしてみましょう。
・準備
AWSのPython SDKである boto3が動くように環境をつくっておきます。
主な作業は、 Comprehend の権限を持ったIAMの作成と、そのAccess Key と Secret Access Keyの設定でしょうか。
(僕は環境変数に入れました。)
これで動くはずなのでやってみます。
ドキュメントはこちらです。
Comprehend — Boto3 Docs 1.14.32 documentation
テキストは青空文庫の走れメロスを拝借しました。
まず、1文のポジネガを判定します。使うメソッドは、 detect_sentiment
です。
本当に簡単に使えます。
import boto3
# 試すテキストを準備する
text1 = "メロスは激怒した。必ず、かの邪智暴虐の王を除かなければならぬと決意した。"
text2 = "メロスは、村の牧人である。笛を吹き、羊と遊んで暮して来た。"
comprehend = boto3.client("comprehend")
for t in [text1, text2]:
comprehend_result = comprehend.detect_sentiment(Text=t, LanguageCode="ja")
print(t)
print(comprehend_result["Sentiment"])
for k, v in comprehend_result["SentimentScore"].items():
print(f" {k}: {v}")
print()
# 以下出力結果
"""
メロスは激怒した。必ず、かの邪智暴虐の王を除かなければならぬと決意した。
NEGATIVE
Positive: 0.00021381396800279617
Negative: 0.8228716850280762
Neutral: 0.17690636217594147
Mixed: 8.087589776550885e-06
メロスは、村の牧人である。笛を吹き、羊と遊んで暮して来た。
NEUTRAL
Positive: 0.0011265947250649333
Negative: 6.331767508527264e-05
Neutral: 0.9988085031509399
Mixed: 1.5915205722194514e-06
"""
みて分かる通り、 Positive(肯定的)/ Negative(否定的)/ Neutral(中立的)/ Mixed(混在) の4つの感情の割合を返してくれます。
複数のテキストをまとめて判定する関数も用意されています。
それが、batch_detect_sentiment
です。
A list containing the text of the input documents. The list can contain a maximum of 25 documents. Each document must contain fewer that 5,000 bytes of UTF-8 encoded characters.
とある通り、 25個までのテキスト(それぞれ5000バイト未満)を順番に判定してくれます。
走れメロスの中に登場する会話文を順番に判定かけてみましょう。
準備として、以下のコードでメロスの会話文の一覧を取得します。
import requests
from bs4 import BeautifulSoup
import re
# 青空文庫 走れメロスのURL
url = "https://www.aozora.gr.jp/cards/000035/files/1567_14913.html"
response = requests.get(url)
# 文字化け対応
response.encoding = response.apparent_encoding
html = response.text
soup = BeautifulSoup(html)
# ルビを取り除く
for tag in soup.findAll(["rt", "rp"]):
# タグとその内容の削除
tag.decompose()
# ルビを取り除いたテキストを取得
text = soup.find(class_="main_text").get_text()
# 改行を消す。
text = text.replace("\r\n", "")
text = text.replace("\n", "")
# 全角スペースを消す
text = text.replace("\u3000", "")
# カッコの内側の文字列を抽出する正規表現パターン
speech_pattern = re.compile("「([^「」]+)」")
# カッコの内側の文字列取得
speech_texts = speech_pattern.findall(text)
全部で62文あるので3回に分けて取得します。
結果は扱いやすい様にPandasのDataFrameに入れておきましょう。
import pandas as pd
sentiment_list = []
positive_list = []
negative_list = []
neutral_list = []
mixed_list = []
for i in range(3):
target_texts = speech_texts[25*i: 25*(i+1)]
comprehend_result = comprehend.batch_detect_sentiment(
TextList=target_texts,
LanguageCode="ja"
)
result_list = comprehend_result["ResultList"]
for r in result_list:
sentiment_list.append(r["Sentiment"])
positive_list.append(r["SentimentScore"]["Positive"])
negative_list.append(r["SentimentScore"]["Negative"])
neutral_list.append(r["SentimentScore"]["Neutral"])
mixed_list.append(r["SentimentScore"]["Mixed"])
# 結果をDataFrameに変換
df = pd.DataFrame(
{
"text": speech_texts,
"sentiment": sentiment_list,
"positive": positive_list,
"negative": negative_list,
"neutral": neutral_list,
"mixed": mixed_list,
}
)
こうして、走れメロスの全台詞に対してポジネガのフラグをつけることができました。
ちなみに最もポジティブだったセリフはこちらです。
text ありがとう、友よ。
sentiment POSITIVE
positive 0.998629
negative 1.88228e-05
neutral 0.00135026
mixed 1.96162e-06
そして、最もネガティブだったのがこれ。
text ‘もう、駄目でございます。むだでございます。走るのは、やめて下さい。もう、あの方をお助けになることは出来ません。
sentiment NEGATIVE
positive 0.000276001
negative 0.996889
neutral 0.00283329
mixed 1.40147e-06
Name: 46, dtype: object
全テキストの結果を見ていくと流石に「ん?」と思う様なものもあるのですが、
概ねしっかりと感情分析ができてる様に思います。