第4章 文本情绪分析基础:情感词典构建、基于规则的情感分析、TF-IDF特征提取

说实话,很多人一上来就搞深度学习做情绪分析,结果数据量不够,模型根本训不动。我个人的经验是——先把手头的规则方法玩透,比什么都强。这一章,咱们就聊聊最基础、也最实用的三样东西:情感词典怎么搭、规则怎么定、TF-IDF怎么用。

核心观点:情绪分析不是非得用神经网络。词典+规则+TF-IDF,这套组合拳能解决80%的工业场景问题。

4.1 情感词典构建:从零搭一个能用的词库

情感词典,说白了就是一张词和情绪分数的映射表。比如「开心」= +2,「恶心」= -3。你可能会问:这玩意儿网上不是有现成的吗?

嗯,是有。但我在项目中遇到过一个问题——通用词典对行业术语完全没反应。比如金融领域,「涨停」明显是正面,「跌停」明显是负面,但通用词典里压根没有。所以,自己动手搭词典,是必修课。

4.1.1 词典的基本结构

我习惯用CSV文件存词典,结构很简单:

词语,极性,强度,词性
开心,正面,2,形容词
愤怒,负面,3,形容词
涨停,正面,2,名词
跌停,负面,2,名词
一般,中性,0,形容词
  • 极性:正面、负面、中性
  • 强度:1-5的整数,越大越强烈
  • 词性:辅助判断,比如否定词要单独处理

我的小技巧:强度值别拍脑袋定。我一般找3个人分别打分,取平均值。比如「痛恨」有人打4分,有人打5分,取4.5再四舍五入。

4.1.2 词典的扩展方法

基础词典大概2000个词就够用了。怎么扩展?我常用的方法有3个:

  1. 同义词扩展:拿已有的正面词,去同义词词典里找兄弟。比如「高兴」→「愉悦」、「欣喜」、「雀跃」。
  2. 领域语料挖掘:收集1000条你所在行业的评论,人工标注50条,然后用PMI算法自动发现新词。
  3. 否定词表:「不」、「没」、「别」、「莫」这些,单独建一个表。它们会翻转情绪极性。

注意:否定词不是万能的。「不怎么样」确实是负面,但「不一般」反而是正面。这种特殊情况,我建议直接加到词典里,别靠规则硬推。

4.2 基于规则的情感分析:简单粗暴但有效

有了词典,下一步就是写规则。规则这东西,你想想看,其实就是一堆if-else。但怎么写得优雅、写得准,是有门道的。

4.2.1 基础打分规则

最简单的规则:遍历句子中的每个词,查词典,正面加分,负面减分,中性忽略。

def basic_sentiment(text, lexicon):
    score = 0
    words = jieba.lcut(text)
    for word in words:
        if word in lexicon:
            score += lexicon[word]['intensity'] * (1 if lexicon[word]['polarity']=='正面' else -1)
    return score

这段代码我刚开始用的时候,准确率大概60%。为什么?因为没处理否定和程度副词。

4.2.2 加入否定词和程度副词

我后来加了两张表:否定词表和程度副词表。规则变成这样:

  • 遇到否定词,翻转后面第一个情感词的极性
  • 遇到程度副词(比如「非常」、「极其」),把后面情感词的强度乘以1.5或2
def advanced_sentiment(text, lexicon, neg_words, adv_words):
    score = 0
    words = jieba.lcut(text)
    i = 0
    while i < len(words):
        word = words[i]
        if word in neg_words and i+1 < len(words):
            next_word = words[i+1]
            if next_word in lexicon:
                score -= lexicon[next_word]['intensity']
                i += 2
                continue
        if word in adv_words and i+1 < len(words):
            next_word = words[i+1]
            if next_word in lexicon:
                multiplier = adv_words[word]  # 比如 '非常':1.5
                score += lexicon[next_word]['intensity'] * multiplier
                i += 2
                continue
        if word in lexicon:
            score += lexicon[word]['intensity']
        i += 1
    return score

效果:加上否定和程度副词后,准确率能到75%左右。对于很多业务场景,这个精度已经够用了。

4.2.3 避坑指南

我曾经踩过一个坑:把「苹果手机不错」判断成了负面。为什么?因为「苹果」在词典里是中性,「手机」也是中性,「不错」是正面,按理说没问题。但分词把「苹果手机」切成了一个词,而这个词不在词典里,直接跳过了。

解决办法:分词前先做词典匹配,把「苹果手机」这种组合词提前加到词典里。

4.3 TF-IDF特征提取:把文本变成数字

规则方法虽然好,但有时候我们需要更精细的特征。TF-IDF就是干这个的——它能把一段话变成一串数字向量。

4.3.1 TF-IDF的原理

说白了,TF-IDF就两个数相乘:

  • TF(词频):这个词在文档里出现了多少次
  • IDF(逆文档频率):这个词在所有文档里有多罕见

为什么会这样设计?因为一个词如果在很多文档里都出现(比如「的」、「是」),那它对区分情绪没什么帮助。反过来,如果只在少数文档里出现(比如「惊艳」),那它很可能是个关键特征。

4.3.2 用sklearn实现TF-IDF

代码其实很简单:

from sklearn.feature_extraction.text import TfidfVectorizer

corpus = [
    "这部电影太精彩了,演员演技炸裂",
    "剧情拖沓,看得我昏昏欲睡",
    "特效不错,但故事太老套"
]

vectorizer = TfidfVectorizer(max_features=100, stop_words='english')
X = vectorizer.fit_transform(corpus)

# 查看特征词
print(vectorizer.get_feature_names_out())
# 查看向量
print(X.toarray())

输出结果是一个矩阵,每一行代表一段话,每一列代表一个词。数值越大,说明这个词对这段话越重要。

我的建议:max_features别设太大。中文场景下,100-200个特征词就够用了。设太多反而会引入噪声。

4.3.3 TF-IDF + 情感词典的组合拳

我个人最喜欢的方式,是把TF-IDF和情感词典结合起来用。怎么做?

  1. 先用TF-IDF提取每段话的关键词
  2. 只对关键词查情感词典打分
  3. 把TF-IDF权重和情感分数相乘,得到加权情绪分

这样做的好处是:那些不重要的词(比如「然后」、「那个」)不会干扰情绪判断,只有真正重要的词才参与打分。

4.4 本章知识体系总览

下面这张图,是我梳理的本章核心逻辑。你看一眼就能明白这三块内容是怎么串起来的:

文本情绪分析基础:三大核心模块 情感词典构建 词表 + 极性 + 强度 基于规则的情感分析 否定词 + 程度副词 TF-IDF特征提取 词频 + 逆文档频率 情绪分数 + 特征向量 可用于分类、回归、可视化 三者关系:词典提供基础数据 → 规则实现快速判断 → TF-IDF补充精细特征 💡 工业实践中,三者常组合使用,准确率可达80%以上

4.5 实战要点总结

最后,我把这一章的核心要点列出来,方便你复习:

模块 核心要点 常见坑
情感词典 极性+强度+词性,三要素缺一不可 行业术语缺失,需要手动补充
规则分析 否定词翻转、程度副词加权 双重否定、特殊搭配要单独处理
TF-IDF 特征词选择、权重计算 特征数太多会引入噪声

一句话总结:情感词典是地基,规则是框架,TF-IDF是精装修。三者配合,才能盖出靠谱的情绪分析系统。

好了,这一章的内容就到这儿。你先把词典搭起来,跑通规则,再试试TF-IDF。相信我,这套组合拳打好了,后面学深度学习都会轻松很多。