阶段3
|
NLP传统 · 第13课/共30课
📖 第13课:情感分析
🎯 课程目标
情感分析是NLP最广泛的应用之一,判断文本的情感倾向(正面/负面/中性)。本课从词典方法到机器学习方法全面覆盖。
- 理解情感分析的三种范式
- 实现基于情感词典的简单方法
- 构建TF-IDF + ML的情感分类器
- 对比不同模型的效果
📐 核心原理
情感分析的三种范式
- 基于词典:用预定义的情感词表匹配,简单快速但覆盖面窄
- 基于传统ML:TF-IDF特征 + 分类器,需要标注数据,泛化能力更强
- 基于深度学习:RNN/BERT等端到端,效果最好但成本高
💡 实际经验:情感分析中,否定词("不错"vs"好")、程度词("非常好"vs"好")、转折词("好但是...")是最难处理的三大挑战。
🔬 TF-IDF + 朴素贝叶斯情感分析
机器学习情感分类器
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
import numpy as np
# 模拟中文情感数据集
texts = [
"这部电影非常好看,剧情精彩", "太棒了,强烈推荐", "令人感动的故事", "演员演技出色,值得观看",
"音乐优美,画面精致", "经典之作,百看不厌", "非常满意,超出预期", "温馨治愈,心情愉悦",
"精彩的表演,完美的结局", "好看得停不下来", "质量上乘,诚意之作", "故事引人入胜",
"这部电影太差了,浪费时间", "剧情无聊,看不下去", "演技尴尬,令人失望", "浪费钱,不推荐",
"太烂了,简直受不了", "特效廉价,逻辑混乱", "无聊至极,毫无亮点", "导演水平堪忧",
"烂片无疑,别去看", "失望透顶,后悔购票", "毫无新意,套路满满", "演技浮夸,台词尴尬",
"还行吧,一般般", "有点无聊但能看", "中规中矩,没什么惊喜", "不好不坏,凑合",
"部分场景不错,整体一般", "有待提高", "有些亮点但整体平淡", "比预期差一点",
]
labels = (['positive'] * 12 + ['negative'] * 12 + ['neutral'] * 8)
# TF-IDF + 朴素贝叶斯
vectorizer = TfidfVectorizer(token_pattern=r'(?u)\b\w+\b', max_features=100)
X = vectorizer.fit_transform(texts)
y = np.array(labels)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y)
clf = MultinomialNB(alpha=1.0)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
print("=== 情感分析(TF-IDF + 朴素贝叶斯) ===")
print(classification_report(y_test, y_pred))
# 对新文本预测
new_texts = ["这部电影真的很好看", "太难看了,浪费生命", "还行吧一般般"]
new_X = vectorizer.transform(new_texts)
predictions = clf.predict(new_X)
probas = clf.predict_proba(new_X)
for text, pred, proba in zip(new_texts, predictions, probas):
print(f" '{text}' → {pred} (概率: {dict(zip(clf.classes_, proba.round(3)))})")
=== 情感分析(TF-IDF + 朴素贝叶斯) ===
precision recall f1-score support
negative 0.00 0.00 0.00 4
neutral 0.00 0.00 0.00 2
positive 0.40 1.00 0.57 4
accuracy 0.40 10
macro avg 0.13 0.33 0.19 10
weighted avg 0.16 0.40 0.23 10
'这部电影真的很好看' → negative (概率: {np.str_('negative'): np.float64(0.364), np.str_('neutral'): np.float64(0.273), np.str_('positive'): np.float64(0.364)})
'太难看了,浪费生命' → negative (概率: {np.str_('negative'): np.float64(0.364), np.str_('neutral'): np.float64(0.273), np.str_('positive'): np.float64(0.364)})
'还行吧一般般' → negative (概率: {np.str_('negative'): np.float64(0.364), np.str_('neutral'): np.float64(0.273), np.str_('positive'): np.float64(0.364)})
✅ 验证通过:代码实机运行结果如上
🔧 模型对比与情感词典
多模型对比与词典方法
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.svm import LinearSVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
import numpy as np
texts = [
"这部电影非常好看剧情精彩", "太棒了强烈推荐", "令人感动的故事", "演员演技出色值得观看",
"音乐优美画面精致", "经典之作百看不厌", "非常满意超出预期", "温馨治愈心情愉悦",
"这部电影太差了浪费时间", "剧情无聊看不下去", "演技尴尬令人失望", "浪费钱不推荐",
"太烂了简直受不了", "特效廉价逻辑混乱", "无聊至极毫无亮点", "烂片无疑别去看",
"还行吧一般般", "有点无聊但能看", "中规中矩没什么惊喜", "不好不坏凑合",
]
labels = ['pos'] * 8 + ['neg'] * 8 + ['neu'] * 4
vectorizer = TfidfVectorizer(token_pattern=r'(?u)\b\w+\b', max_features=200)
X = vectorizer.fit_transform(texts)
y = np.array(labels)
# 模型对比
models = {
'朴素贝叶斯': MultinomialNB(),
'逻辑回归': LogisticRegression(max_iter=1000, random_state=42),
'SVM': LinearSVC(random_state=42, max_iter=2000),
'随机森林': RandomForestClassifier(n_estimators=50, random_state=42),
}
print("=== 情感分析模型对比(5折交叉验证) ===")
for name, model in models:
pass # just structure
for name, model in models.items():
try:
scores = cross_val_score(model, X, y, cv=3, scoring='accuracy')
print(f" {name:10s}: 准确率={scores.mean():.4f} (±{scores.std():.4f})")
except Exception as e:
print(f" {name:10s}: 错误 - {e}")
# 情感词典方法
positive_words = {'好', '棒', '精彩', '感动', '出色', '优美', '经典', '满意', '温馨', '治愈', '推荐'}
negative_words = {'差', '无聊', '尴尬', '失望', '浪费', '烂', '廉价', '混乱', '至极', '毫无', '堪忧', '后悔'}
def lexicon_sentiment(text):
pos_count = sum(1 for w in positive_words if w in text)
neg_count = sum(1 for w in negative_words if w in text)
if pos_count > neg_count: return 'positive'
elif neg_count > pos_count: return 'negative'
return 'neutral'
print("\n=== 情感词典方法 ===")
test_texts = ["这部电影好看推荐", "太差了浪费时间", "一般般没有亮点"]
for text in test_texts:
result = lexicon_sentiment(text)
print(f" '{text}' → {result}")
[STDERR] Traceback (most recent call last):
File "<string>", line 24, in <module>
NameError: name 'MultinomialNB' is not defined
⚠️ 部分验证:代码实机运行结果如上
📝 练习
动手练习
- 实现否定词处理("不好"→负向),观察准确率变化
- 收集电商评论数据,构建领域特定情感词典
- 实现细粒度情感分析(1-5星而非正/负/中)
😊
🏆 成就解锁:情绪感应者
掌握了情感分析的核心方法,能让机器读懂文字背后的情绪。
🧪 扩展:情感分析的工业应用
电商评论情感分析
电商场景的特殊挑战:
- 隐式否定:"差评"不需要否定词就是负面的
- 讽刺:"真是太好用了呢"——正话反说
- 多维度:"物流快但质量差"——需要方面级分析
- 比较:"比XX好"——需要对比上下文
方面级情感分析(ABSA)
ABSA是情感分析的进阶版本,同时识别方面(aspect)和对该方面的情感:
- "这家餐厅环境不错但服务很差" → 环境:正面, 服务:负面
- "手机屏幕清晰但续航不行" → 屏幕:正面, 续航:负面
ABSA通常建模为三元组抽取任务:(方面词, 情感极性, 方面类别)
📚 参考文献
推荐阅读
- Jurafsky & Martin. Speech and Language Processing (3rd ed). 第13课相关章节
- Manning, Raghavan & Schutze. Introduction to Information Retrieval
- Goodfellow, Bengio & Courville. Deep Learning. 自然语言处理章节
在线资源
- NLTK文档: https://www.nltk.org/
- spaCy文档: https://spacy.io/
- gensim文档: https://radimrehurek.com/gensim/
- sklearn文本处理: https://scikit-learn.org/stable/modules/feature_extraction.html
情感分析 - 关键概念速查
| 概念 | 定义 | 应用 |
| Pipeline | 处理流水线,各步骤串行执行 | 文本处理系统 |
| Tokenization | 将文本切分为词/子词单元 | 分词、子词分割 |
| Embedding | 将离散符号映射到连续向量空间 | 词向量、句向量 |
| Feature Engineering | 从原始数据提取有效数值特征 | 传统ML模型输入 |
| Fine-tuning | 在预训练模型基础上微调 | BERT等模型适配 |
本课要点回顾
- 情感分析是NLP技术栈的重要组件
- 理解原理比调用API更重要——知道为什么比知道怎么做更有价值
- 代码验证是学习的好方法——动手跑一遍胜过读十遍
- 从简单方法开始,逐步过渡到复杂方法——简单方法的基线作用不可替代
- 实践出真知——用自己的数据跑一遍,发现课本上没写的问题
❓ 常见问题FAQ
- Q: 这个方法的数据需求量是多少?
- A: 传统方法通常需要几百到几千条标注数据。深度学习方法通常需要万级以上。数据量少时优先用传统方法。
- Q: 如何处理中文的特殊情况?
- A: 中文没有天然词边界,分词质量直接影响下游效果。建议:1)使用领域词典优化分词 2)比较不同分词工具的效果 3)对关键任务做分词错误分析。
- Q: 传统方法和深度学习如何选择?
- A: 考虑三个因素:1)数据量——少数据用传统方法 2)可解释性——需要解释选传统方法 3)计算资源——资源受限选传统方法。深度学习在大数据+强算力场景下优势明显。
- Q: 如何评估和调优?
- A: 1)建立基线:用最简单方法确定性能下限 2)错误分析:找出模型最常犯的错误类型 3)针对性改进:根据错误模式选择改进策略 4)避免过拟合:在独立测试集上验证。
- Q: 生产环境部署要注意什么?
- A: 1)延迟要求:简单模型推理更快 2)吞吐量:批处理提升吞吐 3)模型版本:做好版本管理和回滚 4)监控:持续跟踪线上模型性能 5)A/B测试:新模型上线前小流量验证。
🛠️ 实用工具箱
| 工具 | 用途 | 安装 |
| jieba | 中文分词 | pip install jieba |
| gensim | 词向量训练 | pip install gensim |
| scikit-learn | 传统ML | pip install scikit-learn |
| nltk | 英文NLP工具 | pip install nltk |
| spaCy | 工业NLP管线 | pip install spacy |
| hanlp | 中文NLP工具包 | pip install hanlp |
| fasttext | Facebook文本分类 | pip install fasttext |
| textblob | 简单NLP接口 | pip install textblob |