news 2026/10/30 5:57:14

情感分类大作业源码解析:从情感词典到BiLSTM的完整实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
情感分类大作业源码解析:从情感词典到BiLSTM的完整实现

简介:这份资源是面向高校数据挖掘、机器学习课程学习者与期末大作业需求者的完整情感分类项目源码,围绕情感词典法、传统机器学习与深度学习三条技术路线展开,适合作为课程设计参考或二次开发基础。压缩包共16个文件,约11.84MB,包含3个Python源码文件、2个CSV数据集、6个TXT词典与停用词文件、4张PNG模型结构图及1份Markdown说明文档,覆盖从数据预处理、特征构建到模型训练与结果可视化的完整流程。项目代码注释清晰,零基础也能读懂,下载后可直接运行。目前已有324人学习下载。读者可借此掌握基于情感词典的规则分类、传统机器学习分类器以及CNN、BiLSTM、TextCNN等深度学习模型的实现思路,并参考微博情感数据集完成自己的实验与报告撰写,具备较高的课程作业复用与扩展价值。

1. 从词典到 BiLSTM:一份能跑通的情感分类课程大作业源码

如果你正在为数据挖掘课程设计发愁,或者想找一个能把情感分类从规则方法一路打通到深度学习的完整 Python 项目,这份源码值得认真拆一遍。它把三种技术路线塞进了同一个仓库:基于情感词典的规则打分、传统机器学习(朴素贝叶斯 / SVM 那一套)、以及深度学习(TextCNN、BiLSTM)。数据用的是微博情感 10 万条和 1 万条两个 CSV,词典文件齐全,含程度副词、否定词、停用词、正负情感词表。代码注释密度高,nn.py和ml.py各管一条线,dict.py负责词典法。对新手来说,这是一份能直接跑出结果、看懂流程的参考实现;对熟手来说,它的目录结构和数据处理方式可以当二开底座。下面按「资源是什么 → 怎么用 → 坑在哪」的顺序拆开讲。

2. 三种技术路线的选型逻辑与数据准备

2.1 为什么要把词典法、机器学习和深度学习放在一起

单看情感分类,很多人第一反应是直接上 BERT。但课程大作业的评分逻辑不只是看准确率,还看你对方法演进的理解。词典法解决的是「没有标注数据时怎么起步」,机器学习解决的是「有标注数据后怎么用统计特征」,深度学习解决的是「怎么自动学表征」。三条线放在一起,恰好构成一个完整的方法论叙事。

词典法的核心是情感得分累加:每个情感词有基础极性分,遇到程度副词做乘法放大,遇到否定词做极性翻转。dictionary目录下的degree.txt、inverse_words.txt、positive_simplified.txt、negative_simplified.txt、stopwords.txt就是为这套逻辑服务的。它的优势是零训练、可解释,劣势是对新词和反讽几乎无能为力。

传统机器学习路线在ml.py里,常见做法是把文本转成 TF-IDF 或词袋向量,然后喂给朴素贝叶斯、逻辑回归或 SVM。这条线的关键不在分类器本身,而在特征工程:分词质量、停用词表、n-gram 窗口。weibo_senti_10k.csv适合快速验证,weibo_senti_100k.csv用来跑最终指标。

深度学习路线在nn.py里,包含 TextCNN 和 BiLSTM 两种结构。TextCNN 用不同尺寸的卷积核捕捉局部 n-gram 特征,BiLSTM 用双向序列建模捕捉上下文依赖。image目录下的cnn.png、BiLSTM.png、textcnn.png、100k.png应该是训练曲线或结构示意图,方便写报告时直接引用。

2.2 数据文件的字段结构与读取方式

data目录下两个 CSV 是核心数据源。微博情感数据集通常只有两列:label和review,label 为 1 表示正面,0 表示负面。读取时要注意编码问题,微博数据常见 UTF-8 和 GBK 两种,翻车最多的就是编码报错。

import pandas as pd # 常见做法是先探测编码,再读取 def load_weibo_data(path): try: df = pd.read_csv(path, encoding='utf-8') except UnicodeDecodeError: df = pd.read_csv(path, encoding='gbk') # 统一列名,防止不同版本 CSV 列名不一致 df.columns = ['label', 'review'] # 去掉空文本和重复样本 df = df.dropna(subset=['review']).drop_duplicates(subset=['review']) return df train_df = load_weibo_data('data/weibo_senti_100k.csv') print(train_df['label'].value_counts())

这段代码做了三件事:编码兜底、列名统一、去重去空。参数上,encoding先试 UTF-8 再退 GBK 是处理中文 CSV 的稳妥做法;drop_duplicates的subset指定只按文本去重,避免同一句话重复进入训练集导致指标虚高。value_counts()用来检查正负样本是否均衡,如果偏差超过 3:1,后续训练时需要考虑加权或重采样。

2.3 词典文件的加载与预处理

词典法依赖五个文件,加载顺序和数据结构直接影响打分结果。positive_simplified.txt和negative_simplified.txt是正负情感词表,degree.txt是程度副词及其强度值,inverse_words.txt是否定词表,stopwords.txt是停用词。

def load_dict_file(path): with open(path, 'r', encoding='utf-8') as f: return [line.strip() for line in f if line.strip()] pos_words = set(load_dict_file('dictionary/positive_simplified.txt')) neg_words = set(load_dict_file('dictionary/negative_simplified.txt')) stop_words = set(load_dict_file('dictionary/stopwords.txt')) # 程度副词通常带权重,格式可能是 "词\t权重" degree_dict = {} with open('dictionary/degree.txt', 'r', encoding='utf-8') as f: for line in f: parts = line.strip().split() if len(parts) == 2: degree_dict[parts[0]] = float(parts[1]) inverse_words = set(load_dict_file('dictionary/inverse_words.txt'))

这里用set存情感词和停用词是为了 O(1) 查找,10 万条文本逐条扫描时性能差异明显。degree_dict用字典存权重,因为程度副词需要取值做乘法。注意degree.txt的分隔符可能是制表符也可能是空格,split()不传参能同时处理两种情况。停用词表的作用是在分词后过滤掉「的」「了」「是」这类高频无意义词,但要注意别把否定词误删——否定词必须在停用词之前处理。

3. 词典法打分与机器学习基线怎么落地

3.1 词典法情感得分的计算流程

词典法的打分逻辑可以概括为:分词 → 去停用词 → 扫描情感词 → 检查前窗是否有程度副词或否定词 → 累加得分 → 阈值判极性。难点在于否定词的作用范围,常见做法是只看情感词前 3 个词以内的否定词。

import jieba def sentiment_score(text, pos_words, neg_words, degree_dict, inverse_words, stop_words): words = [w for w in jieba.lcut(text) if w not in stop_words] score = 0 for i, word in enumerate(words): if word in pos_words or word in neg_words: base = 1 if word in pos_words else -1 # 检查前3个词是否有程度副词或否定词 window = words[max(0, i-3):i] for w in window: if w in degree_dict: base *= degree_dict[w] if w in inverse_words: base *= -1 score += base return score # 阈值设为0,大于0判正面,小于0判负面 def predict_dict(text): s = sentiment_score(text, pos_words, neg_words, degree_dict, inverse_words, stop_words) return 1 if s >= 0 else 0

jieba.lcut返回列表,比jieba.cut生成器更方便做窗口索引。窗口大小设为 3 是经验值:太小会漏掉「不是很满意」里的否定,太大会把无关的否定词误算进来。base *= degree_dict[w]和base *= -1的顺序有讲究——先乘程度再翻转极性,和先翻转再乘程度在数学上等价,但代码可读性不同。阈值取 0 意味着中性文本判正面,如果数据偏负面,可以把阈值调到 0.5 或 1。

3.2 传统机器学习的特征工程与模型训练

ml.py的典型流程是:分词 → TF-IDF 向量化 → 分类器训练 → 评估。这里的关键参数是max_features和ngram_range。10 万条微博数据,max_features设 50000 左右能覆盖大部分高频词,ngram_range设(1,2)能捕捉「不 喜欢」这类二元否定。

from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.model_selection import train_test_split from sklearn.svm import LinearSVC from sklearn.metrics import classification_report import jieba def tokenize(text): return ' '.join(jieba.lcut(text)) df = load_weibo_data('data/weibo_senti_100k.csv') df['tokens'] = df['review'].apply(tokenize) X_train, X_test, y_train, y_test = train_test_split( df['tokens'], df['label'], test_size=0.2, random_state=42, stratify=df['label'] ) vectorizer = TfidfVectorizer(max_features=50000, ngram_range=(1,2), min_df=2) X_train_vec = vectorizer.fit_transform(X_train) X_test_vec = vectorizer.transform(X_test) clf = LinearSVC(C=1.0, max_iter=2000) clf.fit(X_train_vec, y_train) y_pred = clf.predict(X_test_vec) print(classification_report(y_test, y_pred))

stratify=df['label']保证训练集和测试集的正负比例一致,避免随机切分导致某一类偏少。min_df=2过滤掉只出现一次的词,降低噪声。LinearSVC比核 SVM 快得多,10 万条数据几分钟能跑完。C=1.0是正则强度,增大 C 会过拟合,减小 C 会欠拟合,可以试 0.1、1、10 三个值看验证集表现。注意fit_transform只在训练集上做,测试集必须用transform,否则词表会泄漏。

3.3 深度学习模型的输入管道

nn.py里的 TextCNN 和 BiLSTM 需要把文本转成定长索引序列。常见做法是构建词表,把每个词映射到整数 ID,短句补零,长句截断。

from collections import Counter import torch from torch.utils.data import Dataset, DataLoader def build_vocab(texts, max_size=30000, min_freq=2): counter = Counter() for text in texts: counter.update(jieba.lcut(text)) # 保留频率达标的词,按频次排序 words = [w for w, c in counter.most_common(max_size) if c >= min_freq] vocab = {w: i+2 for i, w in enumerate(words)} # 0补零,1未知 vocab['<PAD>'] = 0 vocab['<UNK>'] = 1 return vocab class SentimentDataset(Dataset): def __init__(self, texts, labels, vocab, max_len=128): self.texts = texts self.labels = labels self.vocab = vocab self.max_len = max_len def __len__(self): return len(self.texts) def __getitem__(self, idx): words = jieba.lcut(self.texts[idx]) ids = [self.vocab.get(w, 1) for w in words][:self.max_len] ids += [0] * (self.max_len - len(ids)) return torch.tensor(ids), torch.tensor(self.labels[idx])

max_size=30000是词表上限,微博数据 10 万条,3 万词能覆盖绝大多数内容。min_freq=2过滤低频词,减少<UNK>比例。max_len=128是序列长度,微博短文本平均 30 到 50 字,128 足够覆盖长尾。补零用 0,未知词用 1,这两个 ID 不能和真实词冲突。DataLoader的batch_size建议从 64 开始试,显存不够就降到 32。

4. 训练、评估与结果复现的避坑清单

4.1 编码与路径问题

现象:pd.read_csv报UnicodeDecodeError,或者open读词典文件时报FileNotFoundError。

原因:微博 CSV 可能是 GBK 编码,词典文件路径可能带中文目录或相对路径层级不对。

解决:CSV 读取用 try-except 兜底 UTF-8 和 GBK;词典路径统一用os.path.join拼接,先os.path.exists检查再打开。如果项目在 Windows 下解压,注意反斜杠转义问题,用pathlib.Path更稳。

4.2 分词器与停用词表的冲突

现象:词典法准确率异常低,正面文本被判负面。

原因:停用词表里包含了否定词或程度副词,导致「不」「很」被提前过滤,情感词失去修饰。

解决:检查stopwords.txt是否含「不」「没」「很」「太」等词。如果有,要么从停用词表移除,要么调整处理顺序——先做否定词和程度副词检测,再过滤停用词。我一般会在加载停用词后做一次交集检查,把情感修饰词强制保留。

4.3 训练集测试集分布不一致

现象:机器学习模型在测试集上准确率 95%,换一批数据掉到 70%。

原因:train_test_split没有设stratify,或者数据本身有时间顺序,随机切分导致训练集和测试集主题分布不同。

解决:分类任务必须加stratify=labels。如果数据有时间戳,按时间切分比随机切分更接近真实场景。另外检查去重是否在切分之前做——如果先去重再切分,同一文本不会跨集;如果先切分再去重,测试集里可能有训练集的重复样本。

4.4 深度学习过拟合与显存不足

现象:TextCNN 训练 loss 降到 0.1,验证集准确率卡在 80% 不涨;或者 BiLSTM 跑几个 batch 就 OOM。

原因:模型参数量相对数据量偏大,或者batch_size和max_len设置过大。

解决:加 Dropout(TextCNN 在 embedding 后和全连接前各加一层,p=0.5),加 L2 正则,或者减小embed_dim。显存不足优先降batch_size,再降max_len。如果还不行,把 BiLSTM 的hidden_dim从 256 降到 128。常见做法是先用小批量跑通全流程,再逐步放大。

4.5 词典法与模型法结果不可比

现象:词典法准确率 70%,机器学习 90%,直接对比得出结论「词典法没用」。

原因:词典法没有训练过程,它的阈值是人工设定的,而机器学习在测试集上调过参。两者评估口径不同。

解决:报告里分开写,词典法作为 baseline 说明规则方法的局限,机器学习作为统计方法代表,深度学习作为表征学习代表。如果非要对比,给词典法也做一轮阈值搜索,在验证集上选最优阈值,再在测试集上报指标。

5. 从跑通到二开:把这份源码变成你自己的项目

跑通dict.py、ml.py、nn.py三个脚本只是第一步。这份源码真正的价值在于它的可扩展性。我一般会做三件事来验证自己是否真的吃透了它。

第一,换数据集。把weibo_senti_100k.csv换成电商评论或电影评论,观察词典法和机器学习法的指标变化。词典法对领域敏感,电商里的「好评」「差评」在微博词典里可能没有,需要补充领域词表。机器学习法相对稳,但 TF-IDF 词表也要重新拟合。

第二,加一个模型做对比。nn.py里有 TextCNN 和 BiLSTM,可以再加一个FastText或GRU。FastText 本质是词向量平均加线性分类,训练极快,适合做快速基线。加模型时注意复用SentimentDataset和build_vocab,不要重复造轮子。

第三,把评估做细。不要只看 accuracy,加上 precision、recall、F1。情感分类如果正负样本不均衡,accuracy 会骗人。另外画混淆矩阵,看模型是把正面判成负面多,还是反过来。image目录下的100k.png如果是训练曲线,可以对照自己的训练过程看收敛速度是否正常。

from sklearn.metrics import confusion_matrix import seaborn as sns import matplotlib.pyplot as plt cm = confusion_matrix(y_test, y_pred) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues') plt.xlabel('Predicted') plt.ylabel('True') plt.savefig('confusion_matrix.png', dpi=150)

这段代码生成混淆矩阵热力图,fmt='d'保证显示整数,dpi=150够报告用。如果发现某一类召回明显低,回去检查那一类的文本长度分布和词表覆盖。

还有一个容易忽略的点:随机种子。train_test_split的random_state、PyTorch 的torch.manual_seed、NumPy 的np.random.seed都要固定,否则每次跑出来的指标不一样,写报告时没法复现。我习惯在脚本开头统一设一个SEED=42,所有涉及随机的地方都引用它。

从那以后我每次拿到一份课程源码,都强制走一遍「换数据 → 加模型 → 细评估」的流程,确认自己能改、能扩、能解释,才敢说这东西真的跑通了。希望这份拆解帮你少走点弯路。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/30 5:57:11

Java并发核心:JUC常用工具类原理与高并发实战指南

1. 项目概述&#xff1a;为什么“JUC常用并发工具类”是每个Java开发者绕不开的硬核关卡“JUC常用并发工具类”这八个字&#xff0c;听上去像教科书目录里一个平平无奇的小节标题&#xff0c;但在我带过的几十个后端开发团队、参与过的十余个高并发系统重构项目中&#xff0c;它…

作者头像 李华
网站建设 2026/10/30 5:54:52

LYT-NET:轻量化Transformer在低光照图像增强中的应用

1. 项目概述&#xff1a;LYT-NET的轻量化革新在计算机视觉领域&#xff0c;低光照图像增强一直是个棘手问题。传统方法要么计算复杂度高难以部署&#xff0c;要么增强效果生硬不自然。LYT-NET的出现打破了这种困境——这个仅有1.2MB大小的Transformer网络&#xff0c;在保持业界…

作者头像 李华
网站建设 2026/10/30 5:54:03

Kubernetes运维:kubectl命令记录与审计实践

1. Kubectl 命令记录概述作为 Kubernetes 集群管理的瑞士军刀&#xff0c;kubectl 命令行工具是每个云原生工程师的日常必备。但在复杂的生产环境中&#xff0c;我们常常会遇到这样的困境&#xff1a;上周那个能解决当前问题的神奇命令是什么&#xff1f;谁在什么时间执行了哪个…

作者头像 李华
网站建设 2026/10/30 5:53:58

公共卫生时间序列预测实战:XGBoost模型优化与部署

1. 项目背景与核心价值去年参与的一个公共卫生数据分析项目让我印象深刻——当时我们需要基于历史数据预测某地区未来30天的新增病例数。这个看似简单的"回归预测"任务&#xff0c;在实际操作中遇到了数据质量、特征工程、模型选择等一系列挑战。今天就把这个项目的完…

作者头像 李华
网站建设 2026/10/30 5:53:13

HTML5核心技术解析:从语义化标签到性能优化

1. HTML基础概念与历史沿革HTML&#xff08;HyperText Markup Language&#xff09;作为Web开发的基石技术&#xff0c;自1990年由Tim Berners-Lee发明以来&#xff0c;已经经历了多次重大版本迭代。最初仅为科学文档共享设计的标记语言&#xff0c;如今已发展成为支撑全球互联…

作者头像 李华
网站建设 2026/10/30 5:50:14

AI长视频生成技术:挑战与优化方案

1. AI生成长视频的核心挑战长视频生成面临三个主要技术瓶颈&#xff1a;内容连贯性、计算资源消耗和语义一致性。传统视频生成模型通常局限于几秒到几十秒的片段&#xff0c;当扩展到5分钟以上的长视频时&#xff0c;会出现角色变形、场景跳变和时间线混乱等问题。关键突破点在…

作者头像 李华