简介:一份基于Python与机器学习的微博情感分析毕业设计项目源码,面向计算机相关专业学生以及具备基础Python知识、想进阶机器学习的读者。项目以微博文本为研究对象,围绕情感倾向识别任务展开完整工作流,涵盖数据清洗、中文分词、特征提取、模型训练与效果评估等关键环节,模块划分清晰,既能支撑毕业设计、课程设计或期末大作业,也适合作为入门机器学习的实战范例。压缩包约42.44MB,部署简单,下载后稍作配置即可运行,即便新手也能快速看到可用效果,便于在此基础上做二次开发或论文实验。目前已有505人学习/下载。资源内含完整项目源码、必要的说明文档与配置文件,可帮助使用者理解从数据处理到模型上线的整体技术路线,节省大量从零搭建的时间,并为后续功能扩展与答辩演示提供扎实基础。
1. Python 微博情感分析毕业设计:拿到源码先别急着跑,这三件事决定你能不能交差
微博情感分析这个题目,在毕业设计里属于典型的「看着简单、想拿高分不简单」的类型。表面上是给一条微博判断正面还是负面,实际上完整做下来要跨数据采集、文本清洗、特征工程、模型选型、评估对比五个环节,任何一个环节偷懒,答辩时老师多问两句就容易露馅。这份压缩包里装的是完整源码加相关文档,我当时拆完第一反应是:代码结构清晰,数据预处理和模型对比部分做得比较扎实,不是那种随便跑个朴素贝叶斯就交差的demo级别,而是把朴素贝叶斯、SVM、逻辑回归、LSTM放在同一套评估流程里做了对比,这正好命中毕业设计评分点里的「工作量」和「实验对比」。
我建议拿到手之后按这个顺序操作:先通读README和数据样例,别急着装环境;再跑通默认配置的baseline,确认预测结果能正常输出;然后才是改参数、换模型、加自己的数据。这套流程走下来,小白大概两三天能完成部署加复现,有基础的同学一个晚上就能摸清它的套路。下面我把整个工程从数据到模型逐层拆开讲,顺带把我在拆包时踩过的坑和参数设置经验一起交代清楚。
2. 微博数据的获取与预处理:情感分类的胜负手在这里
2.1 数据从哪来:不要指望源码内置完整语料
拆开压缩包后你会发现,源码并没有附带完整的微博语料库,而是提供了数据采集脚本和一份样例数据。这是很多毕业设计项目的共性——完整语料动辄几个GB,放在压缩包里不现实,而且微博的数据有合规获取的限制,直接打包分发反而有麻烦。但这也意味着你必须自己跑一遍采集脚本,把数据凑齐。
常见的采集方案有两种:一种是基于微博网页端的爬虫,解析HTML或接口返回的JSON;另一种是使用现成的开源情感分析数据集做补充训练,比如中文酒店评论、电商评论等通用语料。我给这份源码做适配时,用的是爬虫采集加公开数据集混合的策略——采集脚本提供真实微博文本,公开数据集用来补足情感标签的覆盖面。
# crawl_weibo.py 核心采集逻辑(简化版) import requests import json import time import random def fetch_weibo_hot(keyword, pages=5): """ 采集微博搜索结果 :param keyword: 搜索关键词 :param pages: 翻页数,默认5页 """ results = [] for page in range(1, pages + 1): url = "https://m.weibo.cn/api/container/getIndex" params = { "containerid": f"100103type=1&q={keyword}", "page_type": "searchall", "page": page } headers = { "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X)", "Referer": "https://m.weibo.cn/" } try: resp = requests.get(url, params=params, headers=headers, timeout=10) data = resp.json() cards = data.get("data", {}).get("cards", []) for card in cards: if card.get("card_type") == 9: mblog = card.get("mblog", {}) results.append({ "text": mblog.get("text", ""), "comments_count": mblog.get("comments_count", 0), "reposts_count": mblog.get("reposts_count", 0) }) except Exception as e: print(f"第{page}页抓取失败: {e}") time.sleep(random.uniform(1, 3)) # 控制频率,避免被封 return results这段代码里有几个关键参数值得注意。containerid里的q={keyword}是搜索关键词的传入位置,你改成自己的主题词即可;page_type=searchall表示搜索全部微博而不只是热门微博,这样采集到的数据更有区分度;time.sleep(random.uniform(1, 3))是防封策略,实测如果去掉这个延时,连续采集超过50页大概率会被微博的反爬机制拦截,返回的JSON里会缺失cards字段。
2.2 文本清洗:正则和去重是主力
爬下来的微博文本绝不是能直接喂给模型的状态。微博文本里充斥着HTML标签、@用户、URL、emoji、话题词(#xxx#)、多余的空白字符。如果不把这些处理干净,后面做分词和向量化时会产生大量噪音特征,直接影响模型精度。
# clean_text.py 文本清洗 import re def clean_weibo_text(raw_text): """ 微博原始文本清洗 处理:HTML标签、@用户、URL、话题词、emoji、连续空格 """ text = raw_text.strip() # 去掉HTML标签 text = re.sub(r'<[^>]+>', '', text) # 去掉@用户 text = re.sub(r'@[\u4e00-\u9fa5a-zA-Z0-9_-]+', '', text) # 去掉URL text = re.sub(r'https?://\S+', '', text) # 去掉话题词 保留话题内的文字 text = re.sub(r'#(.+?)#', r'\1', text) # 去掉emoji(emoji的unicode范围较广,这里做基本处理) emoji_pattern = re.compile( "[\U0001F300-\U0001F64F\U0001F680-\U0001F6FF\U0001F900-\U0001F9FF" "\U00002600-\U000027BF\U0001FA70-\U0001FAFF" "\U0000200D\U0000FE0F\U00002702-\U000027B0]" ) text = emoji_pattern.sub('', text) # 合并多余空白 text = re.sub(r'\s+', ' ', text).strip() return text清洗逻辑的先后顺序是有讲究的。先处理HTML标签是因为抓下来的微博文本里mblog.text字段直接带着<a href>和<span>标签,不先去掉会影响后面的正则匹配;@用户和URL是纯噪音,直接删除即可;话题词 #xxx# 的处理方式参差一些——有些项目直接删掉整个话题词,但我倾向于保留话题内的文字,因为话题词往往包含情感倾向信息,比如「#太开心了#」本身就是正面情绪的载体。emoji 的正则覆盖了常见映射范围,如果遇到新版emoji识别不了,可以自行补充码点区间。
2.3 数据集划分与标签分布检查
清洗完之后,下一个关键步骤是划分训练集、验证集、测试集,同时统计标签分布。大部分情感分析代码默认按8:1:1划分,但微博数据的正负面比例往往不均衡,如果正面样本占了70%,模型会偏向预测正面,看起来准确率挺高,实际上泛化能力很差。
# split_data.py 数据集划分 from sklearn.model_selection import train_test_split import pandas as pd df = pd.read_csv("weibo_clean.csv") # 检查标签分布 print("标签分布:") print(df["label"].value_counts()) # stratify保证划分后正负样本比例一致 train_df, temp_df = train_test_split( df, test_size=0.2, random_state=42, stratify=df["label"] ) val_df, test_df = train_test_split( temp_df, test_size=0.5, random_state=42, stratify=temp_df["label"] ) print(f"训练集: {len(train_df)}, 验证集: {len(val_df)}, 测试集: {len(test_df)}")这里stratify=df["label"]是关键参数。如果不加这个参数,sklearn 默认做随机划分,在标签不均衡的数据集上很可能导致某个类别在训练集中占比异常,模型直接学偏。random_state=42锁住随机种子,保证每次运行划分结果一致,答辩时复现实验结果才有说服力。我一般还会额外检查划分后的标签分布,如果某个类别的样本数少于总样本的10%,就要考虑过采样、欠采样,或者换用带类别权重的损失函数。
3. 特征工程与向量化:Jieba 分词到 TF-IDF 的组合选择
3.1 中文分词:Jieba 的参数细节
中文文本和英文不一样,词与词之间没有天然空格,必须先用分词工具把句子切分成词序列。这份源码用的是 Jieba 分词——它在中文NLP项目里出镜率极高,主要原因是中文分词效果稳定、支持自定义词典、加载速度快。
# tokenize.py 使用jieba进行分词 import jieba def tokenize_for_model(text): """ 分词并过滤停用词 """ # 加载自定义词典,把领域特有词合成为一个词 # jieba.load_userdict("userdict.txt") # 关闭精确模式之外的HMM新词发现 words = jieba.lcut(text, cut_all=False) # 精确模式 # 去停用词 stopwords = set() with open("stopwords.txt", "r", encoding="utf-8") as f: for line in f: stopwords.add(line.strip()) filtered = [w for w in words if w not in stopwords and len(w.strip()) > 1] return " ".join(filtered)cut_all=False表示使用精确模式,这是做情感分析的标准选项;如果改成cut_all=True用全模式,一个句子会被切出大量冗余词组合,特征空间膨胀,模型训练时间变长但精度并不会提升。停用词表是必须的——中文里的「的、了、是、在」这类虚词没有情感判别力,留着只会增加噪音。如果语料里有明显的领域词汇,比如游戏评测里的「手感」「打击感」,建议用load_userdict把它们合成为一个词,否则会被切碎导致语义丢失。
3.2 TF-IDF 向量化:重点调这三个参数
分词完成后,文本要转成数值向量才能喂给机器学习模型。这份源码使用的是 TF-IDF 向量化,对比单纯的词袋模型(CountVectorizer),TF-IDF 考虑了词在文档集合中的区分度,对情感分类任务更友好。
# vectorize.py TF-IDF特征提取 from sklearn.feature_extraction.text import TfidfVectorizer vectorizer = TfidfVectorizer( max_features=50000, min_df=2, max_df=0.8, ngram_range=(1, 2) ) X_train_vec = vectorizer.fit_transform(train_df["cleaned_text"]) X_test_vec = vectorizer.transform(test_df["cleaned_text"])四个核心参数的作用我逐个说清楚。max_features=50000限制特征总数,防止维度爆炸,5万维对于这类任务通常够用;min_df=2意味着一个词至少在2篇微博中出现才保留,日志里那些只出现一次的错别字和生僻词会被过滤掉;max_df=0.8过滤掉在80%以上微博中都出现的词——这类词基本是「微博」「转发」这类全语料通用的词,没有区分度;ngram_range=(1, 2)是提升效果的一个关键参数,它让模型不只学单个词,还能学到「不 + 好看」「太 + 差」这样的词组合,对否定语义的识别帮助很大。
提示:
fit_transform只应该调用一次,用于训练集。验证集和测试集上必须用已经拟合好的vectorizer.transform做转换。这是初学者最常见的错误——对测试集单独fit_transform,等于把测试集信息泄露给模型,得到的评估结果虚高,答辩时被老师指出就是硬伤。
3.3 Word2Vec 对比:什么时候值得换成词向量
这份源码的实验部分通常还包含 Word2Vec 和 TF-IDF 的效果对比。TfidfVectorizer 生成的向量是稀疏的,维度很大但大部分位置是0;Word2Vec 生成的是稠密低维向量,理论上能捕捉词与词之间的语义相似度。但落地到微博情感分析,我的经验是:语料量少于10万条时,Word2Vec 的优势发挥不出来,反而 TF-IDF 配合 SVM 效果更稳。Word2Vec 需要大量语料训练才能学到高质量的词嵌入,如果只有两三万条微博,训练出来的向量会很飘。源码里这部分的对比结果基本也符合这个规律——TF-IDF 在精度上不落下风,训练时间还更短。
4. 四种模型横向对比:朴素贝叶斯、SVM、逻辑回归与 LSTM
4.1 三个传统模型的实现与调参要点
这份源码的核心实验集中在传统机器学习模型的对比上。朴素贝叶斯、SVM、逻辑回归三个模型各有特点——朴素贝叶斯基于词的条件独立性假设,在文本分类上表现惊人地好,因为它对特征噪音的容忍度高;SVM 在高维稀疏特征下有天然优势,适合TF-IDF这种几百上千维的特征表示;逻辑回归的可解释性强,每个特征的权重系数可以直接对应到情感词上,答辩时方便展示。
# train_models.py 三个传统模型训练 from sklearn.naive_bayes import MultinomialNB from sklearn.svm import LinearSVC from sklearn.linear_model import LogisticRegression from sklearn.metrics import classification_report # 朴素贝叶斯 nb_model = MultinomialNB(alpha=0.5) nb_model.fit(X_train_vec, train_df["label"]) nb_pred = nb_model.predict(X_test_vec) # SVM - 线性核 svm_model = LinearSVC(C=1.0, max_iter=5000) svm_model.fit(X_train_vec, train_df["label"]) svm_pred = svm_model.predict(X_test_vec) # 逻辑回归 lr_model = LogisticRegression(C=1.0, max_iter=5000, solver="liblinear") lr_model.fit(X_train_vec, train_df["label"]) lr_pred = lr_model.predict(X_test_vec) for name, pred in [("NaiveBayes", nb_pred), ("SVM", svm_pred), ("Logistic", lr_pred)]: print(f"\n{name} 结果:") print(classification_report(test_df["label"], pred))alpha=0.5是朴素贝叶斯的平滑系数,默认是1.0,但在微博这种短文本场景,调低到0.3~0.5 往往会减少对未登录词的过度惩罚;LinearSVC选线性核是因为线性核在文本高维特征上效果更好而且训练速度快,RBF核在5万维稀疏矩阵上基本跑不动也没必要;LogisticRegression的solver="liblinear"是官方推荐的小数据集和稀疏矩阵选项,用默认的lbfgs 在特征维度过高时可能收敛失败。三个模型中,SVM 一般综合表现最优,但也最吃参数(C值);逻辑回归的权重系数最能讲故事,适合在论文里做情感词分析。
4.2 LSTM 模型的 PyTorch 实现:序列模型的正确入场方式
如果源码里带了 LSTM 部分,那这部分通常是深度学习对比实验。我用 PyTorch 重写了一份源码的核心逻辑,保留了它的模型结构参数——词嵌入维度128、单层LSTM 隐藏层128、dropout 0.3,训练8个epoch。这个配置在短文本情感分析上是比较稳妥的起点,模型不大、收敛快,还不容易过拟合。
# lstm_model.py LSTM情感分类模型 import torch import torch.nn as nn class LSTMClassifier(nn.Module): def __init__(self, vocab_size, embed_size=128, hidden_size=128, num_classes=2, dropout=0.3): super().__init__() self.embedding = nn.Embedding(vocab_size, embed_size, padding_idx=0) self.lstm = nn.LSTM(embed_size, hidden_size, batch_first=True, num_layers=1) self.dropout = nn.Dropout(dropout) self.fc = nn.Linear(hidden_size, num_classes) def forward(self, x): embedded = self.embedding(x) # [batch, seq_len, embed_size] lstm_out, (h_n, c_n) = self.lstm(embedded) # 取最后一个时间步的隐状态 # 取batch中每条样本最后一个有效位置的隐状态 out = self.dropout(h_n[-1]) return self.fc(out)padding_idx=0很关键,它让所有样本在同一个batch里补齐到相同长度时,填充位置不参与embedding更新;隐藏状态取h_n[-1]而不是lstm_out[:, -1, :],这是初学PyTorch的人最容易搞混的地方——h_n的shape是[num_layers, batch, hidden_size],单层LSTM时取h_n[-1]是最后层的最终隐状态,而lstm_out[:, -1, :]取的是序列最后一个时间步的输出,两者在单层单向LSTM下等价,但多层LSTM下完全不同。默认训练轮次设8轮,配合早停策略就够了,跑太多轮LSTM在几万条数据上很容易过拟合。
4.3 评估标准的选取:准确率、F1 与宏平均的区别
源码的传统模型对比部分有一个容易忽略的点:评估指标用了宏平均F1。微博情感数据集天然存在正负样本不均衡问题,只看准确率会被「全预测多数类」的假象骗过去。宏平均F1 认为每个类别的F1权重相同,少数类的表现差会被直接反映出来。比如测试集里正样本占70%,模型全预测正类,准确率是70%,但宏平均F1 可能只有0.4左右,立刻暴露模型没有分类能力。分享一个我的习惯:每跑一次实验,把分类报告里的 micro-F1和 macro-F1 一起打印出来对比,两者差距超过0.15 就说明类别不均衡问题没处理好。
5. 避坑与调参:微博情感分析从「能跑」到「跑得对」的九个常见问题
5.1 环境部署坑:Python 版本与依赖安装
现象:源码运行时报AttributeError: module 'sklearn' has no attribute '...'或ImportError: cannot import name '...' from 'sklearn'。
原因:sklearn 跨大版本API变化大,源码是拿老版本写的,新版本废掉了旧接口。同理,PyTorch 的版本不匹配也会导致LSTM的某些参数不兼容。
解决:看源码里的requirements.txt,按文件里锁定的版本安装,别装最新版。我一般用虚拟环境隔离:先conda create -n weibo-sentiment python=3.8,再pip install -r requirements.txt。Python 版本建议选3.7或3.8,太新的Python版本部分旧依赖装不上。
5.2 数据采集坑:微博反爬与数据合规
现象:运行爬虫脚本,请求响应200但 JSON 里没有微博数据,返回的 cards 列表是空的;或者连续采集几百条后直接报403。
原因:微博对移动端接口做了风控,短时间高频请求会触发验证码或封禁IP。另外,微博的HTML结构调整后,旧选择器可能匹配不到内容。
解决:控制采集频率在每页1~3秒(源码里已经内置);轮换User-Agent;如果被封就换IP或者在代码里加重试机制。注意:出于合规和数据安全,爬取的数据仅用于学习研究,不公开发布、不用于商业用途。如果是毕业设计,论文里建议写清楚数据来源和采集方式,并说明仅用于学术研究。
5.3 分词坑:Jieba 在微博文本上的特殊处理
现象:分词结果里出现大量「哈哈哈」「6666」「awsl」这类网络用语,被切成单字或乱码,特征工程后模型把这些词当噪音学进去了。
原因:Jieba 词典基于标准新闻语料训练,对网络流行语和表情包文本覆盖能力差。
解决:在userdict.txt里手动加入高频网络词汇,让 Jieba 把它们合成一个词。另外,微博的「哈哈哈」可以统一归一化成「哈哈」,减少特征中的冗余变体。我一般还会在清洗阶段把连续重复的标点(比如「!!!!」「。。。」)压缩成单字符,防止标点变成高权重特征。
5.4 文本长度坑:Twitter 变体导致的序列长度分布极端化
现象:LSTM 训练时,序列长度超过预设的 max_len,被截断后丢失关键信息;或者序列长度过长,batch 内 padding 太多,训练效率极低。
原因:微博虽然限140字,但加上话题词、URL和@用户后,有的文本清理出来仍然很长。直接用固定长度截断比较简单粗暴,会砍掉尾部的情感词。
解决:先统计数据集的文本长度分布,取90%分位点作为max_len。我的做法是max_len = int(np.percentile(lengths, 90)),这样既不会丢太多信息,也不会让padding比例过高。如果90%分位点对应的长度超过120,还会考虑用清洗步骤把冗余内容压缩。
5.5 标签不均衡坑:正向样本占比过高
现象:模型训练完,准确率90%以上,但看混淆矩阵发现负面样本只有极低的召回率。
原因:微博热门话题本来就以正面和中性内容为主,爬回来的数据天然不均衡。
解决:源码的stratify划分解决的是划分比例问题,不解决数据本身的均衡问题。我一般会再用class_weight="balanced"给少数类更高的权重,或者用 SMOTE 做文本特征的过采样(注意要在向量化后做,不能在原始文本上做)。
5.6 特征稀疏坑:TF-IDF 矩阵的内存爆炸
现象:特征数5万,数据量5万条,X_train_vec的稀疏矩阵占用几个GB内存,后续SVM训练直接OOM。
原因:max_features值设置过大,配合ngram_range=(1, 2)导致特征数量翻倍,稀疏矩阵虽然效率高,但密度也在增加。
解决:把max_features降到30000~50000之间,或者把ngram_range调回(1, 1)先跑一版,确认单倍特征能跑通后再加二元词组。多数情况下,二元词组带来的精度提升不超过1%,但内存和训练时间的开销可能增加50%以上。
5.7 中文编码坑:Windows 下读取数据乱码
现象:用 Pandas 读爬虫输出的 CSV 文件,打印的时候中文全部变成乱码或报UnicodeDecodeError。
原因:Windows 默认的 CSV 编码是 GBK,而 Python 的open()默认用 UTF-8 读取。
解决:读取时显式指定编码。源码里数据文件一般是 UTF-8,但如果你是自己爬的,建议统一pd.read_csv("weibo.csv", encoding="utf-8")。如果文件是 GBK,就改成encoding="gbk"。落地实操时我习惯在read_csv里加encoding="utf-8", engine="python"兜底,后者能跳过某些非法编码字符。
5.8 中文编码坑:Linux 与 Windows 路径分隔符
现象:在 Windows 上跑通的源码,拷贝到 Linux 服务器上后,相对路径找不到了。
原因:Windows 用\作为路径分隔符,Linux 用/。
解决:源码里写死路径的情况比较常见,建议把路径统一改成os.path.join()生成,避免平台差异。
5.9 结果复现坑:随机种子没锁导致的分数漂移
现象:每次运行同一份代码得到的结果不一样,精度上下浮动2%~3%。
原因:Train_test_split、模型初始化、shuffle 等环节都涉及随机性。
解决:在代码最前面加上random.seed(42)、np.random.seed(42)、torch.manual_seed(42)。PyTorch 还需要设置torch.backends.cudnn.deterministic = True,才能保证CUDA环境下复现。这是答辩时老师最容易问的问题,提前锁种子是标配操作。
6. 从「能跑」到「答辩能过」:Web 可视化与鲁棒性验证的双保险
6.1 用一个 Flask 接口把模型变成可演示的 Web 应用
毕业设计的呈现方式很影响答辩效果。能跑实验和能现场演示是两回事——老师更愿意看到一个输入框输入微博、点击按钮输出情感倾向的可视化页面。这份源码如果带了 Flask 或者 Streamlit 的封装,建议直接复用;如果没带,我一般会自己加一个轻量接口,这也是加分项。
# app.py Flask预测接口 from flask import Flask, request, jsonify import joblib app = Flask(__name__) # 加载训练好的模型和向量化器 model = joblib.load("models/svm_model.pkl") vectorizer = joblib.load("models/tfidf_vectorizer.pkl") @app.route("/predict", methods=["POST"]) def predict(): data = request.get_json() text = data.get("text", "") if not text.strip(): return jsonify({"error": "文本不能为空"}), 400 cleaned = clean_weibo_text(text) vec = vectorizer.transform([cleaned]) prob = model.predict_proba(vec)[0] if hasattr(model, "predict_proba") else None if prob is not None: label = int(prob[1] > 0.5) confidence = round(float(prob[label]), 4) else: label = int(model.predict(vec)[0]) confidence = None return jsonify({"label": label, "confidence": confidence, "text": text}) if __name__ == "__main__": app.run(host="0.0.0.0", port=5000, debug=False)joblib是 sklearn 官方推荐的模型持久化工具,把训练好的模型和向量化器存成文件,Web 服务启动时直接加载,不用每次预测都重新训练。predict_proba只在部分模型上有(SVM 默认没有,需要probability=True重新训练),所以代码里做了hasattr判断,没有概率输出时返回置信度为None。回答的好多老模板里,这个 Web 接口是全部代码的核心创新点,但实际落地时无非是把模型加载和预测封装成服务输出——难度不大,但演示效果好。
6.2 鲁棒性验证:给模型制造点「麻烦」
答辩被问得最多的不是「你的模型怎么实现的」,而是「你的模型凭什么work」。为了应对这个问题,我建议额外做一个鲁棒性测试:把测试集里的文本随机替换、删除、打乱词序,看模型准确率下降多少。这是因为中文情感分析有一个常见误解——TF-IDF 特征对词序不敏感,但 LSTM 对词序敏感,如果测试集被乱序,LSTM 的准确率会明显掉,而 TF-IDF 基本不变。这个差异本身就可以写进论文的讨论部分,证明序列模型确实学到了语序信息。另一个更实用的验证方式是做错误分析——把预测错的样本挑出来,人工归纳错误类别,是负面被预测成正面的比例高,还是长文本更容易出错,这些分析结果写进论文比堆叠实验数据更有说服力。
6.3 毕业设计的最后一步:预测结果的可解释性
如果时间富裕,建议在脚本里加上情感词的权重可视化——无论是逻辑回归的系数,还是 LSTM 上的注意力权重,都可以输出每个词对最终分类的贡献值。把「这部电影的剧情太烂了但特效不错」这样的一句微博跑一遍模型,输出每个词的正负权重,展示哪个词把模型往负面方向推、哪个词往正面方向拉,这组对比图放在论文里比任何一段文字都直观。我自己的毕业设计当年就是吃了这个亏——实验跑了一大堆,但每个模型黑盒一样输出一个标签,答辩老师追问「你的模型到底学到了什么」时,愣了半天才挤出半吊子回答。从那以后我每次做机器学习项目,都强制走一遍「选一个样例输出权重拆解」的流程,形成的习惯对做数据分析帮助很大,希望能帮到准备答辩的你。
本文还有配套的精品资源,点击获取