Closed10
Amazon Comprehendで感情分析など
Comrehendでできることを、ざっとPythonで書いてみる。日本語テキストが対象。
作業ディレクトリ作成
mkdir comprehend-work && cd comprehend-work
Python仮想環境作成。最近はuvをよく使う。
uv venv -p 3.12.8
パッケージインストール
uv pip install boto3 loguru
出力
(snip)
+ boto3==1.36.21
(snip)
言語の検出
import boto3
from botocore.exceptions import ClientError
from loguru import logger
import sys
logger.remove()
logger.add(sys.stdout, level="INFO")
class ComprehendDetect:
"""Comprehendの検出機能をカプセル化したクラス"""
def __init__(self, comprehend_client):
"""
:param comprehend_client: Boto3 Comprehendクライアント
"""
self.comprehend_client = comprehend_client
def detect_languages(self, text):
"""
ドキュメントで使用されている言語を検出する
:param text: 分析対象のテキスト
:return: 言語とその信頼度スコアのリスト
"""
try:
response = self.comprehend_client.detect_dominant_language(Text=text)
languages = response["Languages"]
logger.info("{} つの言語を検出しました", len(languages))
except ClientError:
logger.exception("言語の検出に失敗しました")
raise
else:
return languages
if __name__ == "__main__":
comprehend_client = boto3.client("comprehend")
comprehend_detect = ComprehendDetect(comprehend_client)
text = "こんにちは!今日はいいお天気ですね。"
languages = comprehend_detect.detect_languages(text)
print(languages)
出力
[
{
'LanguageCode': 'ja',
'Score': 1.0
}
]
日本語英語混じりだとこうなる
(snip)
text = "こんにちは!今日はいいお天気ですね。On days like this, it's perfect for watching horse racing."
(snip)
出力
[
{
'LanguageCode': 'en',
'Score': 0.6760018467903137
},
{
'LanguageCode': 'ja',
'Score': 0.32314276695251465
}
]
ただ「主要」言語とあるように、それぞれの言語のボリュームによるところがありそうで、以下だと英語のみが返ってきた。
(snip)
text = "こんにちは!今日はいいお天気ですね。I had no luck at all with my horse racing predictions yesterday, and I lost big... I'll do my best next week!"
(snip)
出力
[
{
'LanguageCode': 'en',
'Score': 0.9592218995094299
}
]
名前付きエンティティの検出
import boto3
from botocore.exceptions import ClientError
from loguru import logger
import sys
logger.remove()
logger.add(sys.stdout, level="INFO")
class ComprehendDetect:
"""Comprehendの検出機能をカプセル化したクラス"""
def __init__(self, comprehend_client):
"""
:param comprehend_client: Boto3 Comprehendクライアント
"""
self.comprehend_client = comprehend_client
def detect_entities(self, text, language_code):
"""
ドキュメント内のエンティティ(人物、場所など)を検出する
:param text: 分析対象のテキスト
:param language_code: ドキュメントの言語コード
:return: エンティティとその信頼度スコアのリスト
"""
try:
response = self.comprehend_client.detect_entities(
Text=text, LanguageCode=language_code
)
entities = response["Entities"]
logger.info("{} 個のエンティティを検出しました", len(entities))
except ClientError:
logger.exception("エンティティの検出に失敗しました")
raise
else:
return entities
if __name__ == "__main__":
comprehend_client = boto3.client("comprehend")
comprehend_detect = ComprehendDetect(comprehend_client)
text = "はじめまして、山田太郎です。東京都千代田区永田町に住んでいます。連絡は000-1111-2222までお願いします。"
entities = comprehend_detect.detect_entities(text, "ja")
print(entities)
出力
[
{
'Score': 0.9986088871955872,
'Type': 'PERSON',
'Text': '山田太郎',
'BeginOffset': 7,
'EndOffset': 11
},
{
'Score': 0.9310240149497986,
'Type': 'LOCATION',
'Text': '東京都千代田区永田町',
'BeginOffset': 14,
'EndOffset': 24
},
{
'Score': 0.999465823173523,
'Type': 'OTHER',
'Text': '000-1111-2222',
'BeginOffset': 35,
'EndOffset': 48
}
]
名詞キーフレーズの検出
import boto3
from botocore.exceptions import ClientError
from loguru import logger
import sys
logger.remove()
logger.add(sys.stdout, level="INFO")
class ComprehendDetect:
"""Comprehendの検出機能をカプセル化したクラス"""
def __init__(self, comprehend_client):
"""
:param comprehend_client: Boto3 Comprehendクライアント
"""
self.comprehend_client = comprehend_client
def detect_key_phrases(self, text, language_code):
"""
ドキュメント内のキーフレーズ(主題や重要なフレーズ)を検出する
:param text: 分析対象のテキスト
:param language_code: ドキュメントの言語コード
:return: キーフレーズとその信頼度スコアのリスト
"""
try:
response = self.comprehend_client.detect_key_phrases(
Text=text, LanguageCode=language_code
)
phrases = response["KeyPhrases"]
#logger.info("{} 個のキーフレーズを検出しました", len(phrases))
except ClientError:
logger.exception("キーフレーズの検出に失敗しました")
raise
else:
return phrases
if __name__ == "__main__":
comprehend_client = boto3.client("comprehend")
comprehend_detect = ComprehendDetect(comprehend_client)
text = "昨日の競馬は予想がダメダメで、特に京都はボロ負けでした・・・。今週はいよいよフェブラリーSがあるので頑張りますよ!"
key_phrases = comprehend_detect.detect_key_phrases(text, "ja")
print(key_phrases)
出力
[
{
'Score': 0.9998824596405029,
'Text': '昨日の競馬',
'BeginOffset': 0,
'EndOffset': 5
},
{
'Score': 0.9716150760650635,
'Text': '予想',
'BeginOffset': 6,
'EndOffset': 8
},
{
'Score': 0.8270034193992615,
'Text': '特に京都はボロ負け',
'BeginOffset': 15,
'EndOffset': 24
},
{
'Score': 0.999767005443573,
'Text': '今週',
'BeginOffset': 31,
'EndOffset': 33
},
{
'Score': 0.9988004565238953,
'Text': 'フェブラリーS',
'BeginOffset': 38,
'EndOffset': 45
}
]
感情分析
import boto3
from botocore.exceptions import ClientError
from loguru import logger
import sys
logger.remove()
logger.add(sys.stderr, level="INFO")
class ComprehendDetect:
"""Comprehendの検出機能をカプセル化したクラス"""
def __init__(self, comprehend_client):
"""
:param comprehend_client: Boto3 Comprehendクライアント
"""
self.comprehend_client = comprehend_client
def detect_sentiment(self, text, language_code):
"""
ドキュメント内の全体的な感情を検出する
:param text: 分析対象のテキスト
:param language_code: ドキュメントの言語コード
:return: 感情とその信頼度スコアのリスト
"""
try:
response = self.comprehend_client.detect_sentiment(
Text=text, LanguageCode=language_code
)
logger.info("検出された主な感情: {}.", response["Sentiment"])
except ClientError:
logger.exception("感情の検出に失敗しました")
raise
else:
return response
if __name__ == "__main__":
comprehend_client = boto3.client("comprehend")
comprehend_detect = ComprehendDetect(comprehend_client)
text = "こんにちは!今日はいいお天気ですね。昨日の競馬は全然予想がダメダメで、ボロ負けでした・・・。来週は頑張りますよ!"
sentiment = comprehend_detect.detect_sentiment(text, "ja")
print(sentiment)
出力
{
"Sentiment": "POSITIVE",
"SentimentScore": {
"Positive": 0.9534604549407959,
"Negative": 0.004291504621505737,
"Neutral": 0.035939544439315796,
"Mixed": 0.0063085430301725864
},
"ResponseMetadata": {
"RequestId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"HTTPStatusCode": 200,
"HTTPHeaders": {
"x-amzn-requestid": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"content-type": "application/x-amz-json-1.1",
"content-length": "166",
"date": "Mon, 17 Feb 2025 08:34:34 GMT"
},
"RetryAttempts": 0
}
}
ドキュメント「全体」の感情なので、ミックスされた文章の場合でも、何かしら1つの感情判定となる。
ターゲット感情の分析
これはSDKへのリンクが見当たらなかった。
構文解析
これは日本語は非対応。
import boto3
from botocore.exceptions import ClientError
from loguru import logger
import sys
logger.remove()
logger.add(sys.stdout, level="INFO")
class ComprehendDetect:
"""Comprehendの検出機能をカプセル化したクラス"""
def __init__(self, comprehend_client):
"""
:param comprehend_client: Boto3 Comprehendクライアント
"""
self.comprehend_client = comprehend_client
def detect_syntax(self, text, language_code):
"""
ドキュメントの構文要素を検出する
構文トークンは、名詞、動詞、感嘆詞などの部分として使用されるテキストの部分です。
:param text: 分析対象のテキスト
:param language_code: ドキュメントの言語コード
:return: 構文トークンとその信頼度スコアのリスト
"""
try:
response = self.comprehend_client.detect_syntax(
Text=text, LanguageCode=language_code
)
tokens = response["SyntaxTokens"]
logger.info("{} 個の構文トークンを検出しました", len(tokens))
except ClientError:
logger.exception("構文の検出に失敗しました")
raise
else:
return tokens
if __name__ == "__main__":
comprehend_client = boto3.client("comprehend")
comprehend_detect = ComprehendDetect(comprehend_client)
text = "Hello! It's a beautiful day today. I had no luck at all with my horse racing predictions yesterday, and I lost big... I'll do my best next week!"
syntax = comprehend_detect.detect_syntax(text, "ja")
print(syntax)
出力
[
{
"TokenId": 1,
"Text": "Hello",
"BeginOffset": 0,
"EndOffset": 5,
"PartOfSpeech": {
"Tag": "VERB",
"Score": 0.676778256893158
}
},
{
"TokenId": 2,
"Text": "!",
"BeginOffset": 5,
"EndOffset": 6,
"PartOfSpeech": {
"Tag": "PUNCT",
"Score": 1.0
}
},
{
"TokenId": 3,
"Text": "It",
"BeginOffset": 7,
"EndOffset": 9,
"PartOfSpeech": {
"Tag": "PRON",
"Score": 1.0
}
},
{
"TokenId": 4,
"Text": "'s",
"BeginOffset": 9,
"EndOffset": 11,
"PartOfSpeech": {
"Tag": "VERB",
"Score": 1.0
}
},
{
"TokenId": 5,
"Text": "a",
"BeginOffset": 12,
"EndOffset": 13,
"PartOfSpeech": {
"Tag": "DET",
"Score": 1.0
}
},
{
"TokenId": 6,
"Text": "beautiful",
"BeginOffset": 14,
"EndOffset": 23,
"PartOfSpeech": {
"Tag": "ADJ",
"Score": 0.9999995231628418
}
},
{
"TokenId": 7,
"Text": "day",
"BeginOffset": 24,
"EndOffset": 27,
"PartOfSpeech": {
"Tag": "NOUN",
"Score": 1.0
}
},
{
"TokenId": 8,
"Text": "today",
"BeginOffset": 28,
"EndOffset": 33,
"PartOfSpeech": {
"Tag": "NOUN",
"Score": 1.0
}
},
{
"TokenId": 9,
"Text": ".",
"BeginOffset": 33,
"EndOffset": 34,
"PartOfSpeech": {
"Tag": "PUNCT",
"Score": 1.0
}
},
{
"TokenId": 10,
"Text": "I",
"BeginOffset": 35,
"EndOffset": 36,
"PartOfSpeech": {
"Tag": "PRON",
"Score": 1.0
}
},
{
"TokenId": 11,
"Text": "had",
"BeginOffset": 37,
"EndOffset": 40,
"PartOfSpeech": {
"Tag": "VERB",
"Score": 1.0
}
},
{
"TokenId": 12,
"Text": "no",
"BeginOffset": 41,
"EndOffset": 43,
"PartOfSpeech": {
"Tag": "DET",
"Score": 1.0
}
},
{
"TokenId": 13,
"Text": "luck",
"BeginOffset": 44,
"EndOffset": 48,
"PartOfSpeech": {
"Tag": "NOUN",
"Score": 0.9999996423721313
}
},
{
"TokenId": 14,
"Text": "at",
"BeginOffset": 49,
"EndOffset": 51,
"PartOfSpeech": {
"Tag": "ADV",
"Score": 1.0
}
},
{
"TokenId": 15,
"Text": "all",
"BeginOffset": 52,
"EndOffset": 55,
"PartOfSpeech": {
"Tag": "ADV",
"Score": 0.9999994039535522
}
},
{
"TokenId": 16,
"Text": "with",
"BeginOffset": 56,
"EndOffset": 60,
"PartOfSpeech": {
"Tag": "ADP",
"Score": 0.9999992847442627
}
},
{
"TokenId": 17,
"Text": "my",
"BeginOffset": 61,
"EndOffset": 63,
"PartOfSpeech": {
"Tag": "PRON",
"Score": 1.0
}
},
{
"TokenId": 18,
"Text": "horse",
"BeginOffset": 64,
"EndOffset": 69,
"PartOfSpeech": {
"Tag": "NOUN",
"Score": 1.0
}
},
{
"TokenId": 19,
"Text": "racing",
"BeginOffset": 70,
"EndOffset": 76,
"PartOfSpeech": {
"Tag": "NOUN",
"Score": 0.9998809099197388
}
},
{
"TokenId": 20,
"Text": "predictions",
"BeginOffset": 77,
"EndOffset": 88,
"PartOfSpeech": {
"Tag": "NOUN",
"Score": 1.0
}
},
{
"TokenId": 21,
"Text": "yesterday",
"BeginOffset": 89,
"EndOffset": 98,
"PartOfSpeech": {
"Tag": "NOUN",
"Score": 1.0
}
},
{
"TokenId": 22,
"Text": ",",
"BeginOffset": 98,
"EndOffset": 99,
"PartOfSpeech": {
"Tag": "PUNCT",
"Score": 1.0
}
},
{
"TokenId": 23,
"Text": "and",
"BeginOffset": 100,
"EndOffset": 103,
"PartOfSpeech": {
"Tag": "CCONJ",
"Score": 0.9999390840530396
}
},
{
"TokenId": 24,
"Text": "I",
"BeginOffset": 104,
"EndOffset": 105,
"PartOfSpeech": {
"Tag": "PRON",
"Score": 1.0
}
},
{
"TokenId": 25,
"Text": "lost",
"BeginOffset": 106,
"EndOffset": 110,
"PartOfSpeech": {
"Tag": "VERB",
"Score": 0.9999998807907104
}
},
{
"TokenId": 26,
"Text": "big",
"BeginOffset": 111,
"EndOffset": 114,
"PartOfSpeech": {
"Tag": "ADJ",
"Score": 0.9719122648239136
}
},
{
"TokenId": 27,
"Text": "...",
"BeginOffset": 114,
"EndOffset": 117,
"PartOfSpeech": {
"Tag": "PUNCT",
"Score": 0.9933658242225647
}
},
{
"TokenId": 28,
"Text": "I",
"BeginOffset": 118,
"EndOffset": 119,
"PartOfSpeech": {
"Tag": "PRON",
"Score": 1.0
}
},
{
"TokenId": 29,
"Text": "'ll",
"BeginOffset": 119,
"EndOffset": 122,
"PartOfSpeech": {
"Tag": "AUX",
"Score": 0.9999990463256836
}
},
{
"TokenId": 30,
"Text": "do",
"BeginOffset": 123,
"EndOffset": 125,
"PartOfSpeech": {
"Tag": "VERB",
"Score": 1.0
}
},
{
"TokenId": 31,
"Text": "my",
"BeginOffset": 126,
"EndOffset": 128,
"PartOfSpeech": {
"Tag": "PRON",
"Score": 1.0
}
},
{
"TokenId": 32,
"Text": "best",
"BeginOffset": 129,
"EndOffset": 133,
"PartOfSpeech": {
"Tag": "ADJ",
"Score": 0.9997863173484802
}
},
{
"TokenId": 33,
"Text": "next",
"BeginOffset": 134,
"EndOffset": 138,
"PartOfSpeech": {
"Tag": "ADJ",
"Score": 0.9999744892120361
}
},
{
"TokenId": 34,
"Text": "week",
"BeginOffset": 139,
"EndOffset": 143,
"PartOfSpeech": {
"Tag": "NOUN",
"Score": 1.0
}
},
{
"TokenId": 35,
"Text": "!",
"BeginOffset": 143,
"EndOffset": 144,
"PartOfSpeech": {
"Tag": "PUNCT",
"Score": 1.0
}
}
]
言語ごとのサポート状況は以下参照
日本語が対応しているのは
- エンティティ
- キーフレーズ
- 感情
レスポンスは概ね500ms以内で返ってくるように見える。この手のAPIとしては速い印象。
このスクラップは2025/02/17にクローズされました