通过AI分析人的情绪:基于Python的完整实现指南
在人工智能快速发展的今天,情绪分析(Emotion Analysis)已成为人机交互、心理健康监测、客户服务等领域的重要技术。通过AI分析人的情绪,我们可以从文本、语音、面部表情等多种模态中提取情感信息。本文将重点介绍基于文本的情绪分析,并提供完整的Python代码实现。
情绪分析的核心方法
目前主流的情绪分析方法包括:
-
基于词典的方法:使用情感词典匹配文本中的情感词
-
传统机器学习:使用SVM、朴素贝叶斯等算法
-
深度学习:使用LSTM、BERT等预训练模型
本文将实现后两种方法,让读者理解从基础到前沿的完整流程。
环境准备
首先安装必要的库:
bash
pip install pandas numpy scikit-learn torch transformers nltk matplotlib seaborn
方法一:基于传统机器学习的情绪分析
1. 数据准备
使用NLTK自带的电影评论数据集:
python
import nltk
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import SVC
from sklearn.metrics import classification_report, confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns
# 下载必要的数据
nltk.download('movie_reviews')
nltk.download('stopwords')
nltk.download('punkt')
from nltk.corpus import movie_reviews, stopwords
from nltk.tokenize import word_tokenize
# 加载数据
documents = [(list(movie_reviews.words(fileid)), category)
for category in movie_reviews.categories()
for fileid in movie_reviews.fileids(category)]
# 转换为DataFrame
data = []
for words, sentiment in documents:
data.append({
'text': ' '.join(words),
'sentiment': 1 if sentiment == 'pos' else 0 # 1:正面, 0:负面
})
df = pd.DataFrame(data)
print(f"数据集大小: {len(df)}")
print(df['sentiment'].value_counts())
2. 特征工程与模型训练
python
# 文本预处理函数
def preprocess_text(text):
# 转为小写
text = text.lower()
# 分词
tokens = word_tokenize(text)
# 去除停用词和标点
stop_words = set(stopwords.words('english'))
tokens = [token for token in tokens if token.isalpha() and token not in stop_words]
return ' '.join(tokens)
# 应用预处理
df['processed_text'] = df['text'].apply(preprocess_text)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
df['processed_text'], df['sentiment'],
test_size=0.2, random_state=42, stratify=df['sentiment']
)
# TF-IDF特征提取
tfidf = TfidfVectorizer(max_features=5000, ngram_range=(1, 2))
X_train_tfidf = tfidf.fit_transform(X_train)
X_test_tfidf = tfidf.transform(X_test)
# 训练SVM分类器
svm_model = SVC(kernel='linear', C=1.0, random_state=42)
svm_model.fit(X_train_tfidf, y_train)
# 预测与评估
y_pred = svm_model.predict(X_test_tfidf)
print("\n=== SVM模型评估结果 ===")
print(classification_report(y_test, y_pred, target_names=['负面', '正面']))
# 混淆矩阵可视化
cm = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=['负面', '正面'], yticklabels=['负面', '正面'])
plt.title('SVM情绪分析混淆矩阵')
plt.xlabel('预测标签')
plt.ylabel('真实标签')
plt.show()
方法二:基于深度学习(BERT)的情绪分析
BERT模型能够理解上下文语义,效果远超传统方法。
1. 使用预训练的BERT模型
python
import torch
from transformers import BertTokenizer, BertForSequenceClassification
from torch.utils.data import DataLoader, TensorDataset
from torch.optim import AdamW
from tqdm import tqdm
# 检查GPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f"使用设备: {device}")
# 加载BERT模型和分词器
model_name = 'bert-base-uncased'
tokenizer = BertTokenizer.from_pretrained(model_name)
bert_model = BertForSequenceClassification.from_pretrained(model_name, num_labels=2)
bert_model.to(device)
# 数据预处理
def encode_texts(texts, labels=None, max_length=128):
encodings = tokenizer(
texts.tolist(),
truncation=True,
padding=True,
max_length=max_length,
return_tensors='pt'
)
if labels is not None:
return encodings, torch.tensor(labels.tolist())
return encodings
# 编码数据
train_encodings, train_labels = encode_texts(X_train, y_train)
test_encodings, test_labels = encode_texts(X_test, y_test)
# 创建DataLoader
batch_size = 16
train_dataset = TensorDataset(train_encodings['input_ids'],
train_encodings['attention_mask'],
train_labels)
test_dataset = TensorDataset(test_encodings['input_ids'],
test_encodings['attention_mask'],
test_labels)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size)
# 优化器
optimizer = AdamW(bert_model.parameters(), lr=2e-5)
# 训练函数
def train_epoch(model, loader, optimizer):
model.train()
total_loss = 0
for batch in tqdm(loader, desc="训练中"):
input_ids, attention_mask, labels = [b.to(device) for b in batch]
optimizer.zero_grad()
outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
loss = outputs.loss
total_loss += loss.item()
loss.backward()
optimizer.step()
return total_loss / len(loader)
# 评估函数
def evaluate(model, loader):
model.eval()
predictions = []
actuals = []
with torch.no_grad():
for batch in tqdm(loader, desc="评估中"):
input_ids, attention_mask, labels = [b.to(device) for b in batch]
outputs = model(input_ids, attention_mask=attention_mask)
preds = torch.argmax(outputs.logits, dim=1)
predictions.extend(preds.cpu().numpy())
actuals.extend(labels.cpu().numpy())
return predictions, actuals
# 训练模型
epochs = 3
for epoch in range(epochs):
print(f"\n第 {epoch+1}/{epochs} 轮")
loss = train_epoch(bert_model, train_loader, optimizer)
print(f"训练损失: {loss:.4f}")
# 每轮结束后评估
y_pred_bert, y_true_bert = evaluate(bert_model, test_loader)
from sklearn.metrics import accuracy_score
acc = accuracy_score(y_true_bert, y_pred_bert)
print(f"测试准确率: {acc:.4f}")
# 最终评估
print("\n=== BERT模型评估结果 ===")
print(classification_report(y_true_bert, y_pred_bert, target_names=['负面', '正面']))
方法三:实时情绪分析API
将训练好的模型封装成API服务:
python
from flask import Flask, request, jsonify
import torch
from transformers import BertTokenizer, BertForSequenceClassification
app = Flask(__name__)
# 加载模型(假设已保存)
# torch.save(bert_model.state_dict(), 'emotion_model.pth')
# bert_model.load_state_dict(torch.load('emotion_model.pth'))
# 简单版本:使用预训练模型进行推理
class EmotionAnalyzer:
def __init__(self):
self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
self.tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
self.model = BertForSequenceClassification.from_pretrained('bert-base-uncased', num_labels=2)
self.model.to(self.device)
self.model.eval()
def predict(self, text):
encoding = self.tokenizer(
text,
truncation=True,
padding=True,
max_length=128,
return_tensors='pt'
)
encoding = {k: v.to(self.device) for k, v in encoding.items()}
with torch.no_grad():
outputs = self.model(**encoding)
pred = torch.argmax(outputs.logits, dim=1).item()
sentiment = "正面" if pred == 1 else "负面"
confidence = torch.softmax(outputs.logits, dim=1)[0][pred].item()
return {
'text': text,
'sentiment': sentiment,
'confidence': round(confidence, 4),
'score': pred
}
analyzer = EmotionAnalyzer()
@app.route('/analyze', methods=['POST'])
def analyze():
data = request.json
text = data.get('text', '')
if not text:
return jsonify({'error': '请提供文本'}), 400
result = analyzer.predict(text)
return jsonify(result)
@app.route('/batch_analyze', methods=['POST'])
def batch_analyze():
data = request.json
texts = data.get('texts', [])
if not texts:
return jsonify({'error': '请提供文本列表'}), 400
results = [analyzer.predict(text) for text in texts]
return jsonify({'results': results})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
情绪分析的可视化展示
python
import plotly.graph_objects as go
from plotly.subplots import make_subplots
def create_emotion_dashboard(texts, predictions, confidences):
"""创建交互式情绪分析仪表板"""
# 统计情绪分布
sentiment_counts = ['正面' if p==1 else '负面' for p in predictions]
pos_count = sentiment_counts.count('正面')
neg_count = sentiment_counts.count('负面')
# 创建子图
fig = make_subplots(
rows=1, cols=2,
subplot_titles=('情绪分布', '置信度分布'),
specs=[[{'type': 'pie'}, {'type': 'bar'}]]
)
# 饼图
fig.add_trace(
go.Pie(labels=['正面', '负面'], values=[pos_count, neg_count],
marker=dict(colors=['#2ECC71', '#E74C3C'])),
row=1, col=1
)
# 置信度柱状图
colors = ['#2ECC71' if p==1 else '#E74C3C' for p in predictions]
fig.add_trace(
go.Bar(x=list(range(len(confidences))), y=confidences,
marker_color=colors, text=[f"{c:.2f}" for c in confidences],
textposition='auto'),
row=1, col=2
)
fig.update_layout(
title_text="情绪分析结果仪表板",
showlegend=True,
height=500,
width=1000
)
fig.show()
# 输出详细结果
print("\n详细分析结果:")
for i, (text, sent, conf) in enumerate(zip(texts, sentiment_counts, confidences)):
print(f"{i+1}. {text[:50]}... -> {sent} (置信度: {conf:.2f})")
# 示例使用
sample_texts = [
"这部电影太精彩了,演员演技出色,剧情引人入胜!",
"非常失望,剧情拖沓,浪费时间。",
"平平无奇,没有特别出彩的地方。",
"感动落泪,导演拍得太好了!"
]
# 假设已有模型预测结果
sample_preds = [1, 0, 0, 1]
sample_confs = [0.95, 0.89, 0.67, 0.92]
create_emotion_dashboard(sample_texts, sample_preds, sample_confs)
高级应用:多模态情绪分析
python
# 结合语音和文本的情绪分析示例
import speech_recognition as sr
class MultimodalEmotionAnalyzer:
def __init__(self):
self.text_analyzer = EmotionAnalyzer()
self.recognizer = sr.Recognizer()
def analyze_from_microphone(self, duration=5):
"""从麦克风实时分析情绪"""
print(f"请说话 {duration} 秒...")
with sr.Microphone() as source:
audio = self.recognizer.listen(source, timeout=duration)
try:
# 语音转文字
text = self.recognizer.recognize_google(audio, language='zh-CN')
print(f"识别文本: {text}")
# 情绪分析
result = self.text_analyzer.predict(text)
return result
except sr.UnknownValueError:
return {'error': '无法识别语音'}
except sr.RequestError:
return {'error': '语音识别服务出错'}
# 使用示例
# analyzer = MultimodalEmotionAnalyzer()
# result = analyzer.analyze_from_microphone()
# print(result)
实际应用场景
-
客户服务监控:实时分析客户聊天消息的情绪,当检测到负面情绪时自动升级处理
-
社交媒体分析:批量分析评论、帖子中的情绪倾向
-
心理健康监测:通过分析用户的日记或社交媒体内容,早期发现抑郁倾向
-
教育领域:分析学生反馈,改进教学质量
总结与建议
通过本文,我们实现了:
-
传统机器学习方法(SVM + TF-IDF):准确率约85-90%
-
深度学习方法(BERT):准确率可达92-95%
-
API服务封装:便于集成到实际应用中
选择建议:
-
资源受限或快速原型:使用传统方法
-
追求最佳效果:使用BERT等预训练模型
-
中文场景:使用
bert-base-chinese或roberta-wwm-ext
改进方向:
-
使用更大的预训练模型(RoBERTa、ALBERT)
-
加入数据增强技术
-
进行模型蒸馏以加快推理速度
情绪分析是一个快速发展的领域,随着多模态大模型的出现,未来我们可以更准确地理解人类的复杂情感。希望本文能帮助你快速上手情绪分析项目!
更多推荐
所有评论(0)