深入解析:NLP实战(5):基于LSTM的电影评论情感分析模型研究
深度解析电影《楚门的世界》对现实的挑战 #生活乐趣# #生活分享# #电影评论#
目录
摘要
1. 引言
2. 相关工作
3. 方法
3.1 数据预处理
3.2 模型架构
3.3 训练策略
3.4 交叉验证
4. 实验与结果
4.1 数据集
4.2 实验结果
4.3训练日志
4.4 示例预测
5. 讨论
6. 结论
附录代码
展示和免费下载
摘要
本文提出了一种基于双向LSTM的深度学习模型,用于电影评论的情感分类任务。
通过5折交叉验证方法在标准数据集上评估模型性能,实现了准确的情感极性预测。
实验结果表明,该模型能够有效捕捉文本中的语义特征,在情感分析任务中表现良好。
同时,本文详细介绍了数据预处理、模型架构和训练策略,为相关研究提供了可复现的基准方法。
关键词:情感分析、LSTM、深度学习、文本分类、交叉验证
1. 引言
情感分析是自然语言处理中的重要任务,旨在识别文本中表达的情感倾向。
在电影评论领域,准确的情感分类可以帮助制片方了解观众反馈、优化营销策略。
传统方法依赖于手工特征和浅层机器学习模型,而深度学习模型能够自动学习文本的深层语义表示。
本文构建了一个双向LSTM模型,结合5折交叉验证方法,在公开的电影评论数据集上进行情感分类实验。
主要贡献包括:
(1) 设计了完整的数据预处理流程
(2) 实现了基于注意力机制的双向LSTM模型
(3) 通过交叉验证确保了结果的可靠性
(4) 提供了可复现的实验代码和配置。
2. 相关工作
早期情感分析研究主要基于词典方法和传统机器学习模型(如SVM、朴素贝叶斯)。
随着深度学习的发展,RNN、LSTM和Transformer等模型逐渐成为主流。
Kim等人证明了CNN在文本分类中的有效性,而Zhou等人则展示了LSTM在序列建模中的优势。
本文工作结合了双向LSTM和注意力机制,既能捕捉长距离依赖关系,又能关注情感关键词,在细粒度情感分类(5分类)任务中取得了良好效果。
3. 方法
3.1 数据预处理
数据清洗:去除缺失值,统一转换为小写,移除标点符号和非字母字符
文本规范化:使用NLTK工具进行词形还原(lemmatization)和停用词过滤
词汇表构建:统计词频,保留高频词,建立词到索引的映射(vocab size=17,002)
序列填充:统一截断/填充为长度100的序列(max_len=100)
3.2 模型架构
class SentimentLSTM(nn.Module): def __init__(self, vocab_size, embedding_dim, hidden_dim, output_dim, n_layers, dropout): super().__init__() self.embedding = nn.Embedding(vocab_size, embedding_dim, padding_idx=0) self.lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers=n_layers, bidirectional=True, dropout=dropout, batch_first=True) self.fc = nn.Linear(hidden_dim*2, output_dim) self.dropout = nn.Dropout(dropout)
嵌入层:100维词向量(embedding_dim=100)
双向LSTM:2层256维隐藏状态(hidden_dim=256)
分类层:全连接层输出5维(对应5类情感)
正则化:dropout=0.5防止过拟合
3.3 训练策略
优化器:Adam(lr=0.0001)
损失函数:交叉熵损失
批量大小:64
训练轮次:5
评估指标:分类准确率
3.4 交叉验证
采用分层5折交叉验证(StratifiedKFold),确保每折中各类别比例与原始数据一致。保存每折最佳模型,最终取平均准确率作为模型性能评估。
4. 实验与结果
4.1 数据集
使用电影评论短语数据集,包含:
5类情感标签(0-4对应负面到正面)
0 - negative 0 - 负数1 - somewhat negative 1 - 有点负面2 - neutral 2 - 中性3 - somewhat positive 3 - 有点积极4 - positive 4 - 好评
预处理后17,002词词汇表
示例数据展示:
PhraseSentiment"good for the goose"3 (有点积极)"terrible film"0 (负面)数据集:
4.2 实验结果
5折交叉验证结果:
FoldBest Val Acc155.50%256.02%355.39%455.71%555.00%Mean55.52%训练曲线显示模型收敛良好,无明显过拟合现象。
4.3训练日志
如下:
Loading and preprocessing data...[nltk_data] Downloading package stopwords to[nltk_data] C:\Users\xxx\AppData\Roaming\nltk_data...[nltk_data] Package stopwords is already up-to-date![nltk_data] Downloading package wordnet to[nltk_data] C:\Users\xxx\AppData\Roaming\nltk_data...[nltk_data] Package wordnet is already up-to-date! Using device: cuda Fold 1/5 Epoch 1/5Training: 100%|██████████| 1250/1250 [00:29<00:00, 42.42it/s]Evaluating: 100%|██████████| 313/313 [00:02<00:00, 119.83it/s]Train Loss: 1.224 | Train Acc: 52.19%Val. Loss: 1.202 | Val. Acc: 52.02%Training: 0%| | 0/1250 [00:00
4.4 示例预测
集成模型在测试短语上的预测示例:
Phrase: "This movie is absolutely fantastic!"Predicted Sentiment: 4 (positive)Phrase: "I hated every minute of this terrible film."Predicted Sentiment: 0 (negative)Phrase: "It was okay, nothing special."Predicted Sentiment: 2 (neutral)
5. 讨论
性能分析:55.52%的准确率表明模型能够有效区分5类情感,但仍有提升空间
错误分析:中性(2)与"有点积极"(3)/"有点负面"(1)容易混淆
改进方向:
引入预训练词向量(如GloVe)
增加注意力机制
尝试Transformer架构
6. 结论
本文实现的双向LSTM模型在电影评论情感分析任务中表现良好,5折交叉验证确保了结果的可靠性。该方法可以扩展到其他文本分类场景,代码已实现模块化,便于复现和改进。未来工作将探索更先进的架构和更大的预训练模型。
附录代码
如下:
import pandas as pdimport numpy as npimport torchimport torch.nn as nnfrom torch.utils.data import Dataset, DataLoaderfrom sklearn.model_selection import StratifiedKFoldfrom sklearn.preprocessing import LabelEncoderimport matplotlib.pyplot as pltimport osfrom tqdm import tqdmimport reimport nltkfrom nltk.corpus import stopwordsfrom nltk.stem import WordNetLemmatizerimport jsonfrom collections import defaultdict # 设置随机种子保证可重复性torch.manual_seed(42)np.random.seed(42) # 1. 数据预处理print("Loading and preprocessing data...") # 下载NLTK资源nltk.download('stopwords')nltk.download('wordnet') # 加载数据data = pd.read_csv('data.tsv', sep='\t') # 处理缺失值data = data.dropna() # 编码情感标签label_encoder = LabelEncoder()data['Sentiment'] = label_encoder.fit_transform(data['Sentiment']) # 文本预处理函数stop_words = set(stopwords.words('english'))lemmatizer = WordNetLemmatizer() def preprocess_text(text): text = text.lower() text = re.sub(r'[^a-zA-Z\s]', '', text) words = text.split() words = [lemmatizer.lemmatize(word) for word in words if word not in stop_words] return ' '.join(words) data['Processed_Phrase'] = data['Phrase'].apply(preprocess_text) # 构建词汇表word_counts = defaultdict(int)for text in data['Processed_Phrase']: for word in text.split(): word_counts[word] += 1 sorted_words = sorted(word_counts.items(), key=lambda x: x[1], reverse=True)vocab = {word: i + 2 for i, (word, count) in enumerate(sorted_words)} # 0 for padding, 1 for unknownvocab_size = len(vocab) + 2 # 文本转换为索引序列max_len = 100 def text_to_sequence(text, vocab, max_len=100): sequence = [] words = text.split()[:max_len] for word in words: sequence.append(vocab.get(word, 1)) if len(sequence) best_val_acc: best_val_acc = val_acc torch.save(model.state_dict(), f'models/best_model_fold{fold + 1}.pt') print(f"New best model saved with val acc: {val_acc * 100:.2f}%") # 保存训练曲线 plt.figure(figsize=(12, 6)) plt.subplot(1, 2, 1) plt.plot(history['train_loss'], label='Train Loss') plt.plot(history['val_loss'], label='Validation Loss') plt.title('Loss Curve') plt.xlabel('Epoch') plt.ylabel('Loss') plt.legend() plt.subplot(1, 2, 2) plt.plot(history['train_acc'], label='Train Accuracy') plt.plot(history['val_acc'], label='Validation Accuracy') plt.title('Accuracy Curve') plt.xlabel('Epoch') plt.ylabel('Accuracy') plt.legend() plt.tight_layout() plt.savefig(f'plots/training_curve_fold{fold + 1}.png') plt.close() # 存储结果 fold_results.append({ 'best_val_acc': best_val_acc, 'history': history }) # 打印交叉验证结果 print("\nCross Validation Results:") for i, result in enumerate(fold_results): print(f"Fold {i + 1}: Best Val Acc = {result['best_val_acc'] * 100:.2f}%") mean_acc = np.mean([result['best_val_acc'] for result in fold_results]) print(f"\nMean Validation Accuracy: {mean_acc * 100:.2f}%") # 保存词汇表和模型配置 with open('vocab.json', 'w') as f: json.dump(vocab, f) config = { 'vocab_size': vocab_size, 'embedding_dim': EMBEDDING_DIM, 'hidden_dim': HIDDEN_DIM, 'output_dim': OUTPUT_DIM, 'n_layers': N_LAYERS, 'dropout': DROPOUT, 'max_len': max_len } with open('model_config.json', 'w') as f: json.dump(config, f) print("\nVocabulary and model configuration saved.") # 5. 运行交叉验证if __name__ == "__main__": run_cross_validation() # 测试集成预测 device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 加载模型配置 with open('model_config.json', 'r') as f: config = json.load(f) # 加载词汇表 with open('vocab.json', 'r') as f: vocab = json.load(f) # 加载所有折的最佳模型 models = [] for fold in range(5): model = SentimentLSTM(**{k: v for k, v in config.items() if k != 'max_len'}).to(device) model.load_state_dict(torch.load(f'models/best_model_fold{fold + 1}.pt')) model.eval() models.append(model) # 测试样例 test_phrases = [ "This movie is absolutely fantastic!", "I hated every minute of this terrible film.", "It was okay, nothing special.", "The acting was great but the plot was boring.", "Worst movie I've ever seen in my life." ] print("\nEnsemble Model Predictions:") for phrase in test_phrases: # 预处理 processed_text = preprocess_text(phrase) sequence = text_to_sequence(processed_text, vocab, config['max_len']) sequence = torch.tensor(sequence, dtype=torch.long).unsqueeze(0).to(device) # 集成预测 predictions = [] with torch.no_grad(): for model in models: output = model(sequence) predictions.append(output) avg_prediction = torch.mean(torch.stack(predictions), dim=0) _, predicted = torch.max(avg_prediction, 1) pred_label = label_encoder.inverse_transform([predicted.item()])[0] print(f"Phrase: {phrase}") print(f"Predicted Sentiment: {predicted.item()} ({pred_label})") print()
展示和免费下载
如下:基于LSTM的电影评论情感分析模型研究【代码+10万条数据集+完整训练结果】资源-CSDN文库
训练好的词典:
模型参数:
网址:深入解析:NLP实战(5):基于LSTM的电影评论情感分析模型研究 https://klqsh.com/news/view/120749
相关内容
PyTorch 实例 – 文本情感分析项目电影赏析:经典电影解读与影评分析
影片分析与评论.pdf
基于情感状态的AI音乐疗愈App设计:舒缓与激励
基于虚拟现实技术的宠物互动体验研究.docx
影视作品分析教程(电影分册)
文本分析的三种方法:词频统计、主题建模与情感分析
影视作品分析——影评写作(一)
电影评论家列夫:全方位解析
基于心流理论的骨折复健类APP交互设计分析