こんにちは、なかにしです。
最近はAzureのリソースを試すことにハマってます。
機械学習をやりたくてE資格を取ったのですが、
まずは既存のサービスを見ておこうと思い、色々試している最中です。
今回は AzureのAI群の1つ、感情分析を試して見ようと思います。
Azureの感情分析とは
テキストの感情的なトーンを自動で検出・分類する機能です。
例えば、「このカフェのコーヒーは香りがよくて最高でした。ただ店員さんの対応は少し冷たかったです。」というレビューに対し、以下の判定をしてくれます。
・Positive(肯定的)
・Negative(否定的)
・Neutral(中立)
・Mixed(混合)
さらに、詳細なスコアも教えてくれます。
positive=0.500 neutral=0.210 negative=0.280これにより、大量のレビューの中から効率的に否定的なレビューを集めたり、「ぱっと見は肯定的だが、実は否定的なレビュー」を見逃す確率を抑えたりすることができます。
使用用途としては、
・ABテストの評価
・新商品リリースの評価
・アンケート調査の評価
あたりに使えそうだなと思いました。
やってみた
Azure上で感情分析のリソースを作成する
Azureのリソースから、Foundry > 言語サービスを選択し、作成します。
エンドポイントとキーを取得する
リソースが作成できたら、キーとエンドポイントを確認します。
キーは、1と2のどちらでもOKです。
ローカルで環境構築
今回は、Pythonだけで動かすので、venvを使用して環境構築をしました。
▼ 今回の構成です
▼ requirements.txt
azure-ai-textanalytics==5.3.0
azure-core==1.32.0
python-dotenv==1.0.1コードを書く
メインのコードを書きます。
APIを叩き、結果をprintするだけの機能です。
レビューを評価する というパターンを想定し、reviews.json からレビューを読み込み、それを感情分析のAPIに渡して評価させるような仕組みにしました。
import json
import os
import sys
from pathlib import Path
from azure.ai.textanalytics import TextAnalyticsClient
from azure.core.credentials import AzureKeyCredential
from dotenv import load_dotenv
REVIEWS_PATH = Path(__file__).parent / "reviews.json"
def build_client() -> TextAnalyticsClient:
load_dotenv()
endpoint = os.environ.get("AZURE_LANGUAGE_ENDPOINT")
key = os.environ.get("AZURE_LANGUAGE_KEY")
if not endpoint or not key:
sys.exit("AZURE_LANGUAGE_ENDPOINT と AZURE_LANGUAGE_KEY を .env に設定してください")
return TextAnalyticsClient(endpoint=endpoint, credential=AzureKeyCredential(key))
def analyze(client: TextAnalyticsClient, documents: list[str], language: str = "ja") -> None:
response = client.analyze_sentiment(
documents=documents,
language=language,
show_opinion_mining=True,
)
for i, doc in enumerate(response):
print(f"\n--- Document {i + 1} ---")
print(f"Text : {documents[i]}")
if doc.is_error:
print(f"Error : {doc.error.code} - {doc.error.message}")
continue
print(f"Sentiment: {doc.sentiment}")
scores = doc.confidence_scores
print(f"Scores : positive={scores.positive:.3f} neutral={scores.neutral:.3f} negative={scores.negative:.3f}")
for s_idx, sentence in enumerate(doc.sentences):
print(f" Sentence {s_idx + 1}: {sentence.sentiment} | {sentence.text}")
for mined in sentence.mined_opinions:
target = mined.target
assessments = ", ".join(f"{a.text}({a.sentiment})" for a in mined.assessments)
print(f" Opinion -> target='{target.text}' ({target.sentiment}) assessments=[{assessments}]")
def load_reviews(path: Path) -> tuple[list[str], str]:
if not path.exists():
sys.exit(f"レビューファイルが見つかりません: {path}")
data = json.loads(path.read_text(encoding="utf-8"))
reviews = data.get("reviews", [])
if not reviews:
sys.exit(f"{path} の 'reviews' が空です")
return reviews, data.get("language", "ja")
def main() -> None:
reviews, language = load_reviews(REVIEWS_PATH)
client = build_client()
analyze(client, reviews, language=language)
if __name__ == "__main__":
main()
▼ .envの中身
AZURE_LANGUAGE_ENDPOINT=https://<your-resource-name>.cognitiveservices.azure.com/
AZURE_LANGUAGE_KEY=<your-key>▼ reviews.jsonの中身
{
"language": "ja",
"reviews": [
"このカフェのコーヒーは香りがよくて最高でした。ただ店員さんの対応は少し冷たかったです。",
"新しいスマートフォンはバッテリー持ちが悪いし、カメラも期待外れだった。",
"天気は曇りです。"
]
}実行結果
私はWindowsなので、以下でvenv環境に入り
.\.venv\Scripts\Activate.ps1以下で実行します。
python sentiment.py結果は、以下でした。
--- Document 1 ---
Text : このカフェのコーヒーは香りがよくて最高でした。ただ店員さんの対応は少し冷たかったです。
Sentiment: mixed
Scores : positive=0.500 neutral=0.210 negative=0.280
Sentence 1: positive | このカフェのコーヒーは香りがよくて最高でした。
Opinion -> (positive) assessments=[最高(positive)]
Opinion -> (positive) assessments=[最高(positive)]
Sentence 2: negative | ただ店員さんの対応は少し冷たかったです。
--- Document 2 ---
Text : 新しいスマートフォンはバッテリー持ちが悪いし、カメラも期待外れだった。
Sentiment: negative
Scores : positive=0.000 neutral=0.000 negative=1.000
Sentence 1: negative | 新しいスマートフォンはバッテリー持ちが悪いし、カメラも期待外れだった。
Opinion -> (negative) assessments=[期待外れ(negative)]
--- Document 3 ---
Text : 天気は曇りです。
Sentiment: neutral
Scores : positive=0.020 neutral=0.960 negative=0.010
Sentence 1: neutral | 天気は曇りです。
Opinion -> target='天気' (negative) assessments=[曇り(negative)]人間の直感と感覚が似ているのがすごいですね。
1つ目のレビューに着目すると、後半の「ただ店員さんの対応は少し冷たかったです。」が若干のネガティブになっているが、前半の「このカフェのコーヒーは香りがよくて最高でした。」の「最高」の部分がかなりポジティブなので、部分相殺しつつポジティブが勝っています。
おわりに
感情分析、なかなか面白いですね。
APIはテキストのみ対応ですが、紙のアンケートをOCRして渡したり、音声認識を噛ませてフィジカルAIに組み込んだりと、組み合わせによってはかなり実用性の高い機能だと思いました。
他にもAzure上にAI系のリソースは沢山あるので、1つずつ試してみようと思います!
今回はここまで!
Enjoy Hacking!