Sentiment Analyzer について
Sentiment Analyzerは、基本的な極性分類からアスペクト別の感情分析や感情検出まで、テキスト分析の手法選択とワークフロー構築を支援するスキルです。データや精度要件に応じて、ルールベース、事前学習済みモデル、ファインチューニング、LLMを比較できます。
主な機能
- 01分析手法とトレードオフの比較
- 02感情分析パイプラインと前処理の計画
- 03アスペクト別の感情分析
- 04時間やグループごとの感情追跡
- 05感情、皮肉、比較表現の検出
- 06結果の検証と不確実性の報告
活用シーン
- 01SNSやレビュー向け手法の選定
- 02製品の特定機能に対する感情の把握
- 03複数文書における意見の推移追跡
- 04人手で曖昧な予測を確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ eddiebe147/ claude-settings --skill sentiment-analyzerインストール後、Claude Code で/sentiment-analyzerを入力して読み込まれたか確認します。
詳細
感情分析
感情分析スキルは、テキストに含まれる感情のトーンや意見を理解する感情分析システムの実装を案内します。シンプルなポジティブ/ネガティブ分類から、きめ細かなアスペクトベースの感情分析や感情検出まで、このスキルでは感情分析機能の全領域を扱います。
感情分析は、見かけ以上に複雑です。皮肉、文脈、ドメイン固有の言葉遣い、文化的なニュアンスは、いずれも単純な手法では対応が難しい要素です。このスキルでは、精度要件に応じて、処理が速いルールベースのシステム、ファインチューニング済み分類器、LLM ベースの分析など、適切な手法を選ぶ方法を説明します。
顧客レビュー、ソーシャルメディアでの言及、サポートチケット、アンケートの回答を分析する場合でも、このスキルを活用すれば、ユーザーの真の声を捉えた感情分析を実現できます。
主なワークフロー
ワークフロー 1:感情分析の手法を選ぶ
- 要件を定義します。
- 粒度:2 クラス、3 クラス、連続値のいずれですか?
- アスペクト:全体分析ですか、アスペクトベースですか?
- 感情:感情極性ですか、特定の感情ですか?
- 言語:単一言語ですか、多言語ですか?
- 量:バッチ処理ですか、リアルタイム処理ですか?
- 選択肢を評価します。
手法 速度 精度 カスタマイズ性 最適な用途 ルールベース(VADER) 非常に高速 中程度 限定的 ソーシャルメディア、簡易分析 事前学習済み(RoBERTa) 高速 良好 ファインチューニング可能 一般的なテキスト ファインチューニング済み 高速 最良 データが必要 ドメイン固有 LLM(GPT-4、Claude) 低速 非常に優秀 プロンプトベース きめ細かな分析、複雑な分析 - トレードオフに基づいて選択します。
- 実装を計画します。
ワークフロー 2:感情分析パイプラインを実装する
- テキストを前処理します。
def preprocess_for_sentiment(text): # Preserve sentiment-relevant features text = normalize_unicode(text) # Handle social media conventions text = expand_contractions(text) # don't -> do not text = normalize_elongation(text) # loooove -> love text = handle_negation(text) # Mark negation scope # Preserve but normalize emoji/emoticons text = convert_emoji_to_text(text) # :) -> [HAPPY] return text - 感情を分析します。
class SentimentAnalyzer: def __init__(self, model_type="transformer"): if model_type == "transformer": self.model = pipeline("sentiment-analysis", model="cardiffnlp/twitter-roberta-base-sentiment") elif model_type == "vader": self.model = SentimentIntensityAnalyzer() def analyze(self, text): preprocessed = preprocess_for_sentiment(text) result = self.model(preprocessed) return { "text": text, "sentiment": result["label"], "confidence": result["score"] } - 洞察を得るために集計します。
- 感情の全体的な分布
- 時系列での感情の変化
- セグメント/トピック別の感情
- 結果を検証します。
ワークフロー 3:アスペクトベースの感情分析
- 追跡するアスペクトを特定します。
- 製品の特徴(価格、品質、サービス)
- 体験の側面(速度、精度、親しみやすさ)
- ドメインに合わせたカスタムアスペクト
- テキストからアスペクトを抽出します。
def extract_aspects(text, aspect_list): # Find mentions of known aspects found_aspects = [] for aspect in aspect_list: if aspect.lower() in text.lower(): found_aspects.append(aspect) # Also extract using NER or LLM for unknown aspects extracted = extract_noun_phrases(text) return found_aspects + extracted - アスペクトごとに感情を分析します。
def aspect_sentiment(text, aspects): results = {} for aspect in aspects: # Extract sentences mentioning aspect relevant = extract_aspect_context(text, aspect) # Analyze sentiment of relevant text if relevant: sentiment = analyze_sentiment(relevant) results[aspect] = sentiment return results - ドキュメント全体にわたるアスペクト別の感情を集計します。
クイックリファレンス
| アクション | コマンド/トリガー |
|---|---|
| 感情を分析する | 「[テキスト]の感情を分析」 |
| 手法を選ぶ | 「[ユースケース]に最適な感情分析」 |
| アスペクトベース分析 | 「[レビュー]の特徴別の感情」 |
| 感情を検出する | 「[テキスト]の感情を検出」 |
| 皮肉に対処する | 「感情分析で皮肉に対処する方法」 |
| 結果を集計する | 「感情の傾向を要約」 |
ベストプラクティス
-
感情の手がかりを保持する:重要な手がかりが失われるような前処理は避けてください。
- 句読点を保持します(!! と . の違い)。
- 大文字・小文字のパターンを保持します。
- 絵文字/顔文字を保持します(テキストに変換)。
- 否定表現を明示的に処理します。
-
モデルをドメインに合わせる:事前学習済みモデルにはドメインによる偏りがあります。
- Twitter 向けモデルと製品レビュー向けモデルでは、動作が異なります。
- ファインチューニングするか、ドメインに適したモデルを選びます。
- デプロイ前に、実際のデータでテストします。
-
否定表現を適切に処理する:「悪くない」はネガティブではありません。
- ルールベース:否定の作用範囲を示します。
- ニューラルモデル:通常は自動的に処理します。
- 否定表現のケースを明示的にテストします。
-
文脈を考慮する:感情は文脈によって変わります。
- 「安い」は、低価格帯の商品ではポジティブ、高級品ではネガティブです。
- ニュアンスを捉えるには、アスペクトベースの分析を使用します。
- 可能であれば、周囲の文脈も含めます。
-
人間による検証を行う:機械による感情分析と人間による感情分析は同じではありません。
- サンプルを抽出し、結果を手動で検証します。
- 一致度の指標を計算します。
- 不一致を踏まえて反復的に改善します。
-
不確実性を報告する:すべてのテキストに明確な感情が含まれるわけではありません。
- ニュートラルは有効なクラスです。
- 信頼度の低い予測にはフラグを付けます。
- あいまいなケースでは、予測を控えることも検討します。
高度な手法
LLM を使ったきめ細かな感情分析
複雑な分析には言語モデルを使用します。
def llm_sentiment_analysis(text, aspects=None):
prompt = f"""Analyze the sentiment of the following text.
Text: "{text}"
Provide:
1. Overall sentiment (positive/negative/neutral/mixed)
2. Confidence (0-1)
3. Key positive aspects mentioned
4. Key negative aspects mentioned
5. Notable emotional tones (joy, frustration, surprise, etc.)
{"Also rate sentiment specifically for these aspects: " + ", ".join(aspects) if aspects else ""}
Respond in JSON format."""
response = llm.complete(prompt)
return json.loads(response)
感情検出
ポジティブ/ネガティブを超えて、具体的な感情を検出します。
from transformers import pipeline
# Multi-label emotion classification
emotion_classifier = pipeline(
"text-classification",
model="SamLowe/roberta-base-go_emotions",
top_k=None
)
def detect_emotions(text):
results = emotion_classifier(text)[0]
# Filter to significant emotions
significant = [r for r in results if r["score"] > 0.1]
return sorted(significant, key=lambda x: x["score"], reverse=True)
# Example output:
# [{"label": "admiration", "score": 0.45},
# {"label": "joy", "score": 0.32},
# {"label": "gratitude", "score": 0.28}]
比較感情分析
感情の比較を検出します。
def comparative_sentiment(text):
"""
Detect: "A is better than B" patterns
"""
prompt = f"""Analyze this text for comparative sentiment.
Text: "{text}"
If the text compares entities, identify:
1. Entity A (the preferred/better one)
2. Entity B (the less preferred/worse one)
3. Dimension of comparison (price, quality, etc.)
4. Strength of preference (slight, moderate, strong)
If no comparison, respond with: {{"comparison": false}}
Respond in JSON."""
return llm.complete(prompt)
感情の時系列追跡
時間の経過に伴う感情を分析します。
def sentiment_timeline(documents, time_field, window="day"):
"""
Track sentiment trends over time.
"""
# Analyze each document
results = []
for doc in documents:
sentiment = analyze_sentiment(doc["text"])
results.append({
"timestamp": doc[time_field],
"sentiment": sentiment["score"],
"text": doc["text"]
})
# Aggregate by time window
df = pd.DataFrame(results)
df["window"] = df["timestamp"].dt.floor(window)
trends = df.groupby("window").agg({
"sentiment": ["mean", "std", "count"],
"text": lambda x: list(x)[:3] # Sample texts
})
return trends
皮肉の検出
感情分析の前に皮肉に対処します。
def detect_sarcasm(text):
"""
Detect potential sarcasm indicators.
"""
indicators = {
"exaggeration": bool(re.search(r'\b(best|worst|ever|always|never)\b', text.lower())),
"air_quotes": '"' in text,
"ellipsis": "..." in text,
"positive_negative_mix": has_mixed_signals(text),
"hashtags": "#sarcasm" in text.lower() or "#not" in text.lower()
}
# Use model for detection
sarcasm_score = sarcasm_model.predict(text)
return {
"is_sarcastic": sarcasm_score > 0.5,
"confidence": sarcasm_score,
"indicators": indicators
}
def sentiment_with_sarcasm(text):
sarcasm = detect_sarcasm(text)
base_sentiment = analyze_sentiment(text)
if sarcasm["is_sarcastic"] and sarcasm["confidence"] > 0.7:
# Flip sentiment
return flip_sentiment(base_sentiment)
return base_sentiment
避けるべきよくある落とし穴
- ドメイン固有のテキストに汎用モデルを使用する
- 感情に関連する特徴(絵文字、句読点)を前処理で取り除く
- 否定の処理を無視する
- 中立を、意見がない状態と明示的な中立状態の区別なく扱う
- モデルの出力を人間の判断と照らし合わせて検証しない
- データに皮肉が含まれないと思い込む
- 集計時に極端な感情を過度に重視する
- 確信度や不確実性を示さずに感情を報告する