恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
机器学习网络流量分类毕设全流程:从数据清洗到论文答辩的完整指南
首页
资讯中心
/
机器学习网络流量分类毕设全流程:从数据清洗到论文答辩的完整指南
机器学习网络流量分类毕设全流程:从数据清洗到论文答辩的完整指南
发布时间:2026/10/10 1:09:47
简介这份基于机器学习的网络流量分类方法研究毕业设计项目资料面向计算机、网络工程等相关专业学生可直接用于毕业设计、课程设计或期末大作业提供可运行源码、毕业论文和答辩PPT整体结构清晰便于按需查阅。项目覆盖从数据到模型的完整闭环脚本读取CSV流量数据在nets模块中定义my_cnn、alex_net、vgg_net等网络结构完成训练、测试与准确率记录并保存pkl、pth等模型权重文件便于复现分类结果。压缩包共36个文件包含Python代码、doc论文、pptx答辩文档、模型权重、图片和文本说明等整体约8.88MB代码注释详尽新手也可看懂系统经严格调试简单部署即可运行。已有209人学习下载适合需要完整高分毕设参考、想快速理解机器学习网络流量分类方法并以此为基础完成课程设计或期末大作业的学生。1. 基于机器学习的网络流量分类为什么这个毕设题目最容易做砸每年的毕业设计选题里“基于机器学习的网络流量分类”几乎必占一席很多人看到“机器学习”几个字就直接冲进 sklearn 调参代码能跑、准确率也高一到答辩就被问住数据是怎么来的特征为什么选这些结果能不能复现因为流量分类不是一场算法比赛而是一条从数据集清洗、特征工程、模型对比到论文图表生成、源代码交付的完整链路。这篇文章就按我自己做流量分类项目的顺序从数据选型、特征处理、模型实验讲到论文和 PPT 落地把每一步的决策理由、关键参数和踩坑记录写清楚。适合正在做这个题目的本科生也适合想用机器学习做流量检测的工程师快速建立完整流程。2. 数据集选型与预处理为什么 CICIDS2017 是毕设首选下载后第一件事做什么流量分类项目的第一个决策不是选模型而是选数据集。数据集直接决定了你能讲多少故事、答辩时能扛住多少追问。常见做法是优先从公开的入侵检测数据集里挑因为流量抓取和匿名化自己做的话涉及大量工程细节本科生在毕设周期里基本做不完。选数据集的逻辑很简单老数据集容易跑但特征和攻击类型说服力弱新数据集更贴近真实环境但预处理成本高。我的建议是默认选 CICIDS2017机器配置不够就只取其中一天的 CSV再在论文里说清楚子集划分的原因。2.1 三类公开数据集的取舍KDD99、UNSW-NB15、CICIDS2017 怎么选先说 KDD99 和它的修正版 NSL-KDD。KDD99 是 1999 年模拟环境里采集的连接记录41 维特征攻击类型覆盖四大类。NSL-KDD 去掉了大量冗余记录并把训练集和测试集分布刻意做得不一样很多算法对比论文拿它当基准。但它的缺陷是攻击类型偏老放在今天的流量环境里说服力有限如果你选它答辩时大概率会被问“为什么不用更近的数据集”。UNSW-NB15 是 2015 年的仿真流量49 维特征9 类攻击比 KDD 现代一点特征文档也写得清楚适合做特征工程训练。CICIDS2017 是加拿大 CIC 在真实背景流量上叠加攻击生成的80 多维多向流特征涵盖 Brute Force、DDoS、PortScan、Botnet 等类别最近几年毕设和竞赛几乎默认选它。数据集特征维度攻击类别数据形态适合场景KDD99 / NSL-KDD414 大类已提取连接记录算法对比、教学UNSW-NB15499 类流记录特征工程训练CICIDS20178015 类左右双向流 CSV毕设主力我的选择逻辑是如果只求跑通一个端到端流程并顺利答辩CICIDS2017 是最平衡的选项。它维度够多能支撑你写“特征工程”这一整章类别丰富能画出一张像样的混淆矩阵热力图文档完整数据集打包了解压后就是按周一到周日拆分好的 CSV 文件不需要自己做流重组。缺点也很明显文件大、类别严重失衡、CSV 里有不少脏数据。UNSW-NB15 作为备选适合你机器内存不足的时候用49 维特征跑起来舒服类别数也够写对比实验。还有一个常见操作是把 CICIDS2017 里的某一天单独拿出来比如 Wednesday 同时包含 DDoS 和 PortScan既能控制训练时间又不影响论文结构。总之别一上来就全量加载先看清单。2.2 拿到 CSV 后的第一件事清洗、去重、看标签分布很多人拿到 CSV 直接 read_csv 然后就开始 fit这是实际项目中几乎人人踩过的坑。CICIDS2017 的原始 CSV 有几个固定毛病列名普遍带前导空格部分攻击片段里的数值列会出现 Infinitypandas 读进来后不处理树模型勉强能忍SVM 和神经网络直接崩还有完全重复的行和大量 NaN。所以拿到压缩包后第一步永远是写一个清洗脚本把数据变成可训练的 DataFrame。import pandas as pd import numpy as np from sklearn.model_selection import train_test_split df pd.read_csv(Wednesday-WorkingHours.csv) df.columns [c.strip() for c in df.columns] # 去掉列名前导空格 df.replace([np.inf, -np.inf], np.nan, inplaceTrue) # Infinity 统一转 NaN df.dropna(inplaceTrue) # 直接丢弃含空值行 df.drop_duplicates(inplaceTrue) # 原始数据里有重复行 label_col Label # 清洗后列名已去空格 print(df[label_col].value_counts()) # 第一步永远是看标签分布这段代码的逻辑很直接先做列名规范化否则后面写特征列列表时你会发现复制粘贴的列名死活取不到数据。replace 把正负无穷都换成 NaN是为了让 dropna 能一次清干净不然填充逻辑会漏掉 Infinity。drop_duplicates 默认按整行去重处理后的样本量会明显下降这是正常的论文里要把清洗前和清洗后的样本数都写出来老师很爱问这个数差在哪。最后打印 value_counts主要看正常类占比多少、每个攻击类最少有几条这直接决定后续要不要做欠采样或加 class_weight。这里还要注意dropna 会把一些有价值但局部缺失的行删掉如果你的数据量大删掉几千行无伤大雅如果数据本身少就得改成按列缺失率筛选而不是一刀切。2.3 类别不均衡与数据划分分层抽样不是可选项看完成标签分布你基本会被吓一跳BENIGN 往往占七成以上而 Web Attack 这类攻击可能只有几千条。如果不处理不均衡模型学到的就是“全部判正常”的捷径准确率高得吓人但攻击类别召回率趋近于零。正确做法分两层第一切分数据集时必须用 stratify 做分层抽样保证每个类在训练集和测试集里的比例一致第二先不做欠采样跑一个随机森林基线看混淆矩阵里哪些类被吃掉再针对性地降采样正常类样本。train_df, test_df train_test_split( df, test_size0.2, stratifydf[label_col], # 按标签比例分层切分 random_state42 # 固定随机种子保证结果可复现 ) print(train_df[label_col].value_counts() / len(train_df)) print(test_df[label_col].value_counts() / len(test_df))stratify 参数的意义是让训练集和测试集里的类别比例都等于原始数据比例这样少数类不会在测试集里只剩几百条F1 的波动也会小很多。random_state 必须固定否则你每次运行得到的数据划分都不同论文里的实验结果就成了“一次性结果”这是代码可复现的基本要求。注意我这里切的是 DataFrame 而不是特征数组因为后续要做特征工程保持整体切分能避免索引错位。还有一个常见做法是只对训练集做处理测试集保持原始分布这样才能模拟真实环境里的比例。很多学生在这里偷懒直接在切分前整个数据集做欠采样最后测试集也是平衡的答辩时被问“真实流量里攻击比例有这么高吗”就答不上来。3. 特征工程把原始 CSV 变成机器学习模型真正吃的东西筛选边界怎么设数据集就位以后最容易被忽略的是特征工程。很多机器学习实战教程直接拿全量特征塞给模型但 CICIDS2017 里 80 多维特征并不都是有效的有些特征之间高度相关有些特征本身就是为了作弊而存在的。比如包含源 IP、目的 IP、源端口、目的端口这些标识字段模型可能学到的是“某个 IP 是攻击者”而不是攻击行为本身。所以特征工程这章的核心任务是把原始 CSV 里真正能描述流量行为的列挑出来构造少量有解释力的新特征再用筛选方法压缩维度。别小看这步它直接决定你论文里“特征分析”章节有没有东西可写。3.1 流特征优先毕设为什么不建议自己抓包做深度特征流量分类有两个方向一个是基于流特征的分类用流的持续时间、包长均值、包数量这些统计量另一个是原始报文深度特征比如提取载荷内容或做字节序列 embedding。毕设阶段我强烈建议只做流特征。原因是原始报文方向需要你自己处理 TCP 流重组、报文去重、时间戳对齐一套流程下来光数据预处理就能写一篇论文而且深度学习方法如果没有 GPU训练周期长得无法控制。CICIDS2017 里的 80 多列正好全是流统计特征拿来做传统机器学习分类是教科书级别的匹配。你要做的特征工程不是从 pcap 抓包开始而是在这 80 多列里做筛选和构造。这里的另一个考量是“可解释性”。答辩时老师会问“你为什么选这个特征”如果你用的是流持续时间、平均包长这类有明确物理含义的统计量能当场解释如果你用的是某个深度网络学出来的向量解释起来非常被动。所以我的策略是保留原始统计特征构造两三个比例特征再用随机森林重要度做筛选。这样论文里既能写“特征从何而来”又能写“筛选依据”逻辑闭环。3.2 构造特征子集与标签编码一个可复制的代码流程下面是特征工程阶段最常见的一套代码流程包含三件事剔除标识字段、构造新特征、完成标签编码。# 1. 取特征列排除标识列与标签列 drop_cols [Label, Flow ID, Source IP, Destination IP, Source Port, Destination Port, Timestamp] feature_cols [c for c in train_df.columns if c not in drop_cols] X_train train_df[feature_cols].copy() X_test test_df[feature_cols].copy() # 2. 处理无穷值与缺失值统一填 0 X_train X_train.replace([np.inf, -np.inf], np.nan).fillna(0) X_test X_test.replace([np.inf, -np.inf], np.nan).fillna(0) # 3. 构造比例特征前向平均包长 / 后向平均包长 X_train[Fwd_Bwd_Ratio] X_train[Fwd Pkt Len Mean] / (X_train[Bwd Pkt Len Mean] 1e-9) X_test[Fwd_Bwd_Ratio] X_test[Fwd Pkt Len Mean] / (X_test[Bwd Pkt Len Mean] 1e-9) # 4. 标签编码二分类攻击为 1正常为 0 y_train train_df[label_col].map(lambda v: 0 if v BENIGN else 1) y_test test_df[label_col].map(lambda v: 0 if v BENIGN else 1)先说剔除字段的逻辑。Flow ID、IP、端口这些标识字段一旦保留模型会直接记忆 IP 和端口的组合换一批数据就失效这在机器学习里叫数据泄漏的变体。有些毕设为了跑出高准确率故意保留端口特征答辩被追问后会很狼狈。我一般连端口也一起删因为端口在动态环境里漂移很大。构造比例特征是为了捕捉“请求小、响应大”这种行为模式加 1e-9 是防止除数为 0这个常数项在论文里也要提一句显示你不是随手写的。标签编码这里先做二分类因为 CICIDS2017 的多分类标签里包含大量相近攻击类型直接把 15 类全做分类混淆矩阵会乱得没法解释答辩时也讲不清。建议主体实验做二分类作为一篇完整毕设可以留一组多分类实验放在扩展章节里但不作为核心结论。3.3 特征筛选的边界方差阈值与重要度到底该怎么用特征筛选最容易犯两个错一个是完全不筛80 多列全丢给模型论文里放一张十几页的特征重要性图另一个是只看随机森林的重要度排序把 top 10 留下其余全删。我的做法是三步走第一步用方差阈值去掉几乎恒定不变的列第二步用随机森林跑一次全量特征得到重要度排序第三步把重要度低的特征逐个手动检查是噪音就删是有物理含义但被相关特征压制的就保留。from sklearn.feature_selection import VarianceThreshold sel VarianceThreshold(threshold0.01) # 方差低于 0.01 的特征视为常数特征 sel.fit(X_train) keep_cols X_train.columns[sel.get_support()] X_train_sel X_train[keep_cols] X_test_sel X_test[keep_cols] print(f原始特征数: {X_train.shape[1]}, 筛选后: {X_train_sel.shape[1]})VarianceThreshold 的作用是删除那些数值基本不变的特征比如某些标志位字段在数据集里几乎没有变化留着只会增加噪声。threshold 设 0.01 是经验值取值逻辑是“如果特征的标准差接近 0说明它对区分类别没有贡献”。注意这里有个坑必须先只对训练集 fit再对训练集和测试集做同样的 transform如果你对全量数据 fit会在特征筛选中引入测试集信息这就是数据泄漏。筛完特征后再算一遍随机森林重要度只保留累计重要度达到 90% 以上的前十几个特征其余在论文里用“与保留特征高度相关为降低冗余而剔除”一句话带过即可。特征筛选不是越多越好也不是越少越好标准是“能用最少特征解释最多攻击行为”。4. 模型训练与对比实验随机森林、XGBoost、SVM 的参数怎么调才写得出论文模型部分是整个毕设最像“机器学习”的地方也是最容易被老师看穿你有没有真做实验的环节。很多人直接用 sklearn 默认参数跑一遍输出准确率 99%然后得意地贴上论文。但默认参数的随机森林在 CICIDS2017 上确实能有很高准确率因为正常类占比太高模型只需要学一个“大数类”就能得分。所以这一章的关键不是“把模型跑起来”而是“让对比实验有说服力”。你需要做三件事固定评估协议、调整每个模型最核心的几个参数、用 F1 而不是准确率评估结果。这三件事做完论文里就有了一张逻辑完整的实验对比表。4.1 评估协议先于模型交叉验证和测试集的位置不能搞混机器学习应用流程里最忌讳的就是边调参边看测试集结果。正确的顺序是先把数据划分为训练集和测试集并冻结在训练集上做交叉验证选参数选完参数后用全部训练数据重新训练一次最后在测试集上跑一次得到最终指标。这个过程听起来简单但实际中很多学生会把测试集也拿进交叉验证里导致最终分数虚高复现时对不上。from sklearn.model_selection import cross_val_score from sklearn.ensemble import RandomForestClassifier X X_train_sel # 已经筛选好的训练特征 y y_train base_rf RandomForestClassifier(n_estimators200, random_state42, n_jobs-1) scores cross_val_score(base_rf, X, y, cv5, scoringf1_macro) print(CV F1 macro:, scores.mean(), /-, scores.std())cross_val_score 的作用是把训练数据切成 5 份轮流用其中 4 份训练、1 份验证最后取平均 F1。cv5 是常规选择如果你时间充裕可以试 10 折但 CICIDS2017 样本量足够大5 折和 10 折结果差异很小。scoring 参数用 f1_macro 而不是 accuracy因为后者在不均衡数据上会骗人。注意这里的 n_jobs-1 让随机森林并行训练但如果你的机器核心少或者内存小要改成 n_jobs4否则可能直接把电脑跑死。交叉验证阶段只看验证集上的 F1不要记录测试集任何信息哪怕是无意中瞟一眼都不行这是实验的基本纪律。4.2 三个模型的必调参数一张表写清楚改什么、不改什么随机森林、XGBoost、SVM 是流量分类论文里出现频率最高的三个模型。很多学生把每个模型的十几个参数都列进论文看起来像调参大师实则答辩时一个都解释不清。正确的做法是只调三个最关键的参数其余用默认值并把默认值作为对比基线。下面是三个模型的参数表按我自己的经验给出常用范围和说明。模型核心参数常用范围参数作用与踩坑说明随机森林n_estimators100 ~ 500树的数量越大越稳超过 300 后收益递减设太大会让训练时间翻倍随机森林max_depthNone 或 20 ~ 40不限制深度容易过拟合限制后泛化更稳论文里写 None 要有合理解释随机森林class_weightbalanced缓解类别不均衡比手动欠采样更省心XGBoostlearning_rate0.05 ~ 0.1学习率越小需要更多轮数0.3 默认值偏激进容易过拟合XGBoostmax_depth5 ~ 8与随机森林不同XGBoost 深度设太深会显著过拟合XGBoostsubsample / colsample_bytree0.8 / 0.8列和行采样降低方差是 XGBoost 最有用的两个参数线性 SVMC1 ~ 10正则强度C 越大越容易过拟合CICIDS2017 全量数据建议 C1线性 SVMclass_weightbalanced不均衡场景必开否则少数类全被吞这张表的重点是随机森林和 XGBoost。随机森林的 n_estimators 和 max_depth 是你能在论文里讲清楚的两个量树多了减少方差深度限制防止过拟合。XGBoost 的 learning_rate 和 max_depth 组合是它的灵魂如果你只用默认参数跑 XGBoost效果未必比随机森林好甚至可能更差因为默认学习率 0.3 在流量数据上很容易过拟合。SVM 这里我写的是线性 SVM也就是 LinearSVC因为非线性 SVM 在几十万样本上训练时间以小时计毕设时间耗不起。如果你的数据集比较大直接用线性 SVM 当对比即可在论文里注明“由于数据规模较大采用线性核保证训练效率”这是合理的工程决策。4.3 训练与评估代码怎么写结果表怎么填调完参以后用完整训练集训练模型在测试集上做最终评估。这里有一个细节交叉验证阶段你已经用同一份训练集评估过模型最后再用全部训练集训练一次理论上会和交叉验证的平均分基本一致如果差距过大说明数据切分有问题或者随机种子没固定。from sklearn.metrics import classification_report, confusion_matrix final_model RandomForestClassifier( n_estimators300, max_depth30, class_weightbalanced, n_jobs-1, random_state42 ) final_model.fit(X_train_sel, y_train) y_pred final_model.predict(X_test_sel) print(classification_report(y_test, y_pred, target_names[BENIGN, ATTACK]))classification_report 会输出每个类别的精确率、召回率和 F1这三列就是你论文实验对比表的核心数据。注意看 macro avg 这一行它把两个类别的 F1 做算术平均比 accuracy 更能反映模型在攻击类上的表现。拿到报告以后把随机森林、XGBoost、SVM 三份结果整理成一张表格格式统一为“精确率 / 召回率 / F1”再加上训练时间一列这张表就是论文第 4 章的骨架。训练时间的记录方式也很重要用 time 模块包一下 fit 调用即可别用肉眼看手机计时答辩时会被质疑。还有一个容易被忽略的输出混淆矩阵。随机森林训练完后直接调用 confusion_matrix 并画成热力图你能一眼看到正常类里有多少被误判成攻击、攻击类里有多少漏网。这张图不仅是论文素材更是你写“误分类分析”章节的依据。很多学生只放一张热力图不解释为什么误判答辩老师问起来就冷场。建议你把误判样本的特征分布拉出来看一眼通常会发现是短连接类型的攻击被当成了正常流量因为它的包长统计量和正常流量太接近。这个观察写进论文比单纯调参有价值得多。5. 避坑流量分类毕设最常翻车的 5 个现场流量分类项目的特点是数据管道长、环节多任何一环出错都会让最终结果“看起来挺好一问就倒”。这里把我见过最多的 5 个翻车现场写成排查记录每条都按现象、原因、解决三步来写你对照自己项目检查即可。这些坑有一个共同特征它们都不会让代码报错只会让你得到一份用不了的结果所以尤其险恶。5.1 五个高频坑现象、原因与解决办法坑一训练集和测试集的类别分布完全不一样F1 虚高。现象是训练时交叉验证分数很高但测试集分数低得离谱。原因是切分数据时没有用 stratify少数类攻击全部跑到了训练集测试集里几乎只剩正常流量。解决方法是回到第二章检查切分代码把 stratify 参数加上并把随机种子固定。坑二特征列里有字符串模型报错。现象是 fit 时报 ValueError提示无法处理字符串。原因是 CICIDS2017 某些 CSV 里存在非数值列或者你保留了一些协议字段比如把 Transport Layer 协议名直接当成了特征。解决方法是检查 feature_cols 列表把所有 dtype 不是数值类型的列剔除或者在读入后调用 df.select_dtypes(include[number])。这一步看似简单但实际里很多人会漏看个别列。坑三随机森林准确率极高但攻击召回率几乎为 0。现象是测试集上 accuracy 达到 98% 以上但 classification_report 里 ATTACK 的召回率只有 0.1 左右。原因是正常类占比过高模型没有学到攻击模式。解决办法是给模型加 class_weightbalanced或者在数据层面做针对性的欠采样。我自己的顺序是先开 class_weight如果 F1 还不够再考虑采样。一个常见的误区是直接对全量数据做随机欠采样把攻击类也一起删了结果少数类更少。欠采样的对象应该只是正常类。坑四SVM 训练两小时还没跑完。现象是 fit 之后程序长时间无响应CPU 满负荷运转。原因是你用了非线性核的 SVC而样本量太大。解决方法是换 LinearSVC并调整 C 参数如果还是慢就先对训练集做一次随机采样把训练样本控制在 5 万条以内在论文里注明“为控制训练时间对训练集进行了子采样”。这样做牺牲一点准确率但能保证实验跑完比交不上结果强得多。坑五答辩复现时结果对不上。现象是你本地跑出的准确率和论文里写的差好几个百分点。原因是随机种子没固定、特征筛选时用全量数据 fit、或者测试集没有冻结。解决方法是把实验流程脚本化成固定的三步读数据、清洗、切分所有随机操作固定 random_state并且把最终实验结果保存成 CSV。答辩时现场只跑预测脚本不重新训练这样既快又稳。提示这些坑里最值得警惕的是坑五。很多学生把手动点选、临时修改变量的习惯带进毕设代码最终代码能跑但没人能复现老师一句“把你的环境拿来再跑一遍”就穿帮了。6. 论文与 PPT把实验结果变成答辩现场能复现的最后一公里代码和实验做完毕设才算完成一半。源代码、论文和 PPT 三者的关系不是各自独立而是互相印证老师拿到代码能跑通看论文能找到对应图表看 PPT 能把握主线。我见过不少代码实验结果都不错但论文里找不到一张和代码输出对得上的图答辩时现场演示又报错最后分数不如代码简单但交付完整的人。所以最后一公里我建议你用一套脚本把图表和数值自动导出论文直接引用这些生成结果保证“所见即所得”。6.1 论文结构对应代码目录让老师按图索骥论文目录不要按网上模板硬套而要和你的代码文件结构一一对应。常见的对应方式是第二章写数据集对应代码里的 data_preprocess.py第三章写特征工程对应 feature_engineering.py第四章写实验对应 train_evaluate.py。每一章引用图表时在代码注释里标注生成该图的脚本和随机种子答辩时可以靠这些注释快速定位。这里有很多学生忽略的一点是论文里提到每个实验数据比如清洗前样本数、清洗后样本数、特征维度都要在代码的输出日志中找到出处。答辩评委通常不会仔细看每个公式但一定会抽查几个关键数字是否对得上。6.2 PPT 页面节奏与图表规范十分钟讲清楚一个毕设答辩 PPT 我会控制在 10 到 12 页节奏是背景和问题 2 页、数据集介绍 2 页、特征工程 2 页、模型与实验结果 3 页、结论与改进 2 页。图表规范上最核心的三张图是类别分布条形图、特征重要性 Top 10 柱状图、混淆矩阵热力图。类别分布图要标注清楚不均衡比例这是你后面所有实验选择的依据特征重要性图只放前 10 个特征名字太长就横过来画混淆矩阵热力图必须用颜色归一化否则攻击类只有几千条在热力图里几乎看不见颜色差异。PPT 里不要贴大段代码但可以把关键参数表放上去比如随机森林的 n_estimators 和 max_depth这几行参数就是你答辩时“讲清楚做了什么”的证据。6.3 一键导出全部图表与结果的小脚本一个能让我自己心安的小技巧是写一份 export_results.py负责把论文里所有图表重新生成一次。这个脚本的输入是测试集和训练好的模型文件输出是实验对比表、混淆矩阵图、特征重要性图、训练时间记录。所有输出命名带日期和随机种子比如 rf_confusion_42.png。这样答辩前一天跑一遍所有素材的生成时间统一绝对不会出现“论文里这张图是上周的代码已经改过一版”的情况。写这个脚本本身花不了太多时间但它能把你的交付状态从“一堆散落文件”变成“一个标准工程包”源代码和论文的对应关系也一下子清楚了。另一个实际经验是把最终实验数据写进一个 CSV而不是直接截图论文里的表格。答辩时如果有人问到你某个类别精确率为什么比另一个低你可以当场用脚本从 CSV 里算出对应指标而不是翻 PPT。这种能当场验证细节的习惯是拿高分的一个关键。我自己做过一个流量分类相关的项目后最深的感受是机器学习的黑匣子并不可怕可怕的是连你自己都无法复现的实验结果。把所有随机种子、数据切分、参数配置固化在脚本里结果表自动生成这套流程习惯让我后来的每个项目都少了许多返工。希望这篇笔记能帮你在做流量分类毕设时少走几步弯路。本文还有配套的精品资源点击获取