Pythonで感情分析

chatbotの瞼を感情(悲しい、嬉しい)で動きを作るための仕掛け、

Pythonで形態素解析と、事象を参照してスコア化できるライブラリがあるのでそれを使う

辞書(wago.121808.pn)はLLMが教えてくれた東北大のサイトからダウンロードしてます

<Python script : LLM会話での現在形態>

必要なライブラリは、spacy/jaconv/ja-ginzaをpip install、spacyは多言語の形態素解析のできるライブラリでラズパイ5でもそこそこの速度で動作可能、辞書のサイズはおよそ五千語です

import spacy
import jaconv

# --- 辞書ロード関数 ---
def normalize_to_hiragana(text):
    """表記をひらがなに正規化"""
    return jaconv.kata2hira(jaconv.z2h(text, kana=True, digit=True, ascii=True))

def load_combined_sentiment_dict(paths):
    sentiment = {}
    for path in paths:
        with open(path, encoding='UTF-8') as f:
            for line in f:
                cols = line.strip().split('\t')
                if len(cols) < 2: continue label = cols[0] # "ポジ"や"ネガ"を抽出 word = cols[1] # 単語を抽出 # スコアをラベルに応じて決定 if "ネガ" in label: score = -1.0 elif "ポジ" in label: score = 1.0 else: score = 0.0 # 中立の場合 sentiment[word] = score # 単語とスコアを登録 return sentiment # --- 感情分析処理 --- def analyze_sentiment(text, sentiment_dict, nlp): doc = nlp(text) positive_count = 0 negative_count = 0 print("=== マッチ単語とスコア ===") for token in doc: lemma = token.lemma_ # 語幹 print(f"処理中: {token.text}({lemma})") # 辞書に単語がマッチした場合 if lemma in sentiment_dict: score = sentiment_dict[lemma] print(f"マッチ: {lemma} → {score:+.1f}") if score > 0:
                positive_count += 1
            elif score < 0: negative_count += 1 total_words = len([token for token in doc if not token.is_punct]) # 句読点を除く単語数 sentiment_score = positive_count - negative_count # ポジティブ単語数 - ネガティブ単語数 normalized_score = sentiment_score / total_words * 10 if total_words > 0 else 0  # スコアの正規化

    result = "neutral"
    if normalized_score > 0:
        result = "positive"
    elif normalized_score < 0:
        result = "negative"

    print(f"\n感情スコア: {normalized_score:+.1f}")
    print(f"判定結果: {result}")
    print(f"ポジティブ単語数: {positive_count}")
    print(f"ネガティブ単語数: {negative_count}")

    return {
        "score": normalized_score,
        "positive_count": positive_count,
        "negative_count": negative_count,
        "result": result
    }

# --- メイン関数 ---
def main():
    text = """シンドラーとはね、第二次世界大戦中に、ユダヤ人をナチスから守った人だよ。彼は、ドイツのオースヴィッツ強制収容所から、たくさんのユダヤ人を助けたんだ。すごい人だよね!"""

    print("GiNZAロード中...")
    nlp = spacy.load("ja_ginza")

    print("辞書読み込み中...")
    sentiment_dict = load_combined_sentiment_dict([
        "wago.121808.pn"
    ])

    print(f"\n分析対象: {text}\n")
    analyze_sentiment(text, sentiment_dict, nlp)

if __name__ == "__main__":
    main()

<実行結果>

クリスマスのことを語っている文章を入力にすると、

% python emotion.py
GiNZAロード中...
辞書読み込み中...

分析対象: うん、そうだよ!プレゼントとか、クリスマスツリーとか、すごく楽しいよね!

=== マッチ単語とスコア ===
処理中: うん(うん)
処理中: 、(、)
処理中: そう(そう)
処理中: だ(だ)
処理中: よ(よ)
処理中: !(!)
処理中: プレゼント(プレゼント)
処理中: と(と)
処理中: か(か)
処理中: 、(、)
処理中: クリスマスツリー(クリスマスツリー)
処理中: と(と)
処理中: か(か)
処理中: 、(、)
処理中: すごく(すごい)
処理中: 楽しい(楽しい)
マッチ: 楽しい → +1.0
処理中: よ(よ)
処理中: ね(ね)
処理中: !(!)

感情スコア: +0.7
判定結果: positive
ポジティブ単語数: 1
ネガティブ単語数: 0

感情スコアは+1 ~ -1の間に治るようにしたいから乗算してます、上限と下限もこの値で区切るようにした方がいいだろうね、

 

admin