恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
基于UNSW-NB15数据集的网络攻击检测:机器学习全流程实战
首页
资讯中心
/
基于UNSW-NB15数据集的网络攻击检测:机器学习全流程实战
基于UNSW-NB15数据集的网络攻击检测:机器学习全流程实战
发布时间:2026/10/13 2:50:44
简介这是一份基于UNSW-NB15数据集开展网络攻击检测的机器学习毕业设计资源面向计算机相关专业的学生、老师及企业开发者涵盖决策树、逻辑回归、KNN等典型分类算法的Python实现可直接用于毕设、课程设计或初期项目演示。压缩包解开后共4个文件核心为3个Python脚本和1个说明文档整体仅12KB结构清楚部署简单能够快速复现二分类检测流程并观察各算法表现。目前已有143人学习下载适合希望以现成源码快速启动实验、在此基础上修改或扩展功能的中初级学习者。资源内附的说明与应用逻辑便于使用者理解从数据读入、模型训练到结果输出的完整过程可用于论文复现、答辩演示或作为同类入侵检测课题的起步模板。1. 用 UNSW-NB15 数据集做网络攻击检测毕设里性价比最高的选题之一当你在 UNSW-NB15 数据集上把随机森林跑到 90% 以上准确率时真正值得注意的不是那个数字而是测试集上的 F1 波动。标题里这个项目——机器学习算法 UNSW-NB15 数据集的网络攻击检测——几乎是毕设选题里的“标准答案”数据集公开、标签齐全、场景明确一套流程跑下来预处理、算法对比、图形化评估全都有论文里的图表基本齐了。它能解决的核心问题是用机器学习判断一条网络流量是正常还是攻击并进一步识别攻击类型。适合两类人毕业设计或课程设计需要“能运行、能讲解、有图表”完整方案的在校生以及刚进入入侵检测方向、想拿真实数据集练手的从业者。价值在于链路完整从 CSV 原始数据到混淆矩阵每一步都有明确输出不是那种跑完就扔的黑匣子 Demo。先提醒一个常见的认知偏差很多人以为模型一 fit、打印个准确率就算完工但这个数据集有特有的坑比如训练测试分布不一致、类别不平衡、字符特征编码顺序错位。接下来把数据加载、预处理、训练、评估全路线以及最容易翻车的节点一次讲透。2. 数据预处理与特征工程把 49 列原始流量变成模型能吃的矩阵UNSW-NB15 的原始 CSV 并不是拿来就能直接喂给 sklearn 的。官方发布的数据集已经划分好了训练集和测试集但里面混着 id、源 IP、端口这类标识列还有 proto、service、state 这类字符列不处理直接 fit 会当场报错。这一章把数据加载、清洗、编码、归一化整条流水线过一遍后面训练脚本才能一跑就通。2.1 加载数据用官方划分不要自己随机切分这个数据集的官方发布页提供了训练集和测试集两个 CSV训练集约 17.5 万条测试集约 8.2 万条每条 49 列。毕设里最稳的做法是直接用官方划分不要自己切。因为论文评审会关注测试集出处官方划分的测试集在同方向的对比实验里就是基准自己随机切分反而容易被质疑结果不可比。import pandas as pd train pd.read_csv(UNSW_NB15_training-set.csv) test pd.read_csv(UNSW_NB15_testing-set.csv) print(训练集:, train.shape) print(测试集:, test.shape) print(train[label].value_counts()) # 正常流量 label0攻击流量 label1逻辑说明read_csv 不传额外参数就能成功读入说明文件完整。shape 和 value_counts 用来确认数据规模与正负样本比例这两步是后续所有处理的前提先确认数据没问题再往下走。参数说明label 列只有 0/1 两个取值0 是正常流量1 是攻击流量。如果 value_counts 打印出来比例严重偏离比如攻击样本只有几千条说明下载的文件可能不完整要回到数据源重新获取。2.2 剔除标识列并把字符特征编码49 列里id、srcip、sport、dstip、dsport 是网络流量的标识信息不能进模型。剩下的特征里proto、service、state 是字符型sklearn 不接受字符串必须先编码。这里用 LabelEncoder 而不是对所有 object 列做 OneHot原因是 service 列基数很大OneHot 会把特征列扩展到几百维训练和预测都变慢而树模型对 LabelEncoder 产生的整数顺序并不敏感。drop_cols [id, srcip, sport, dstip, dsport] feature_cols [c for c in train.columns if c not in drop_cols [attack_cat, label]] from sklearn.preprocessing import LabelEncoder def encode_categorical(data, encoders): X data[feature_cols].copy() for col in feature_cols: if X[col].dtype object: le encoders.get(col, LabelEncoder()) X[col] le.fit_transform(X[col].astype(str)) encoders[col] le return X train_encoders {} X_train_raw encode_categorical(train, train_encoders) X_test_raw encode_categorical(test, train_encoders) # 复用整套编码器逻辑说明encode_categorical 用传入的 encoders 字典第一次 fit 生成映射测试集只做 transform 不重新 fit。这样保证同一个字符取值在训练和测试里被映射成同一个数字这是最容易出错的地方如果在测试集上重新 fit 一套编码特征含义就完全错位模型评估结果直接失真。参数说明astype(str) 是为了避免某列里混入 NaN 导致 fit_transform 报错。LabelEncoder 遇到训练集没出现过的字符串会抛“未知类别”错误这个在避坑第 5.2 节会专门处理。2.3 缺失值填充与特征顺序固定这个数据集里部分列确实存在 null。常见处理是 fillna(0)网络流量里时长、负载长度缺失时填 0语义上等价于“该属性无记录”对树模型的切分影响很小。另一个值得留意的细节是把 feature_cols 存成 pickle训练和预测共用同一份列顺序否则会出现特征错位这种极难排查的问题。import joblib X_train_raw X_train_raw.fillna(0) X_test_raw X_test_raw.fillna(0) feature_order list(X_train_raw.columns) joblib.dump(feature_order, feature_order.pkl) # 预测阶段还要用 print(特征数量:, len(feature_order)) print(训练集剩余 NaN 数量:, int(X_train_raw.isna().sum().sum()))逻辑说明fillna(0) 放在编码之后统一执行比一列一列处理省事。feature_order.pkl 是后悔药模型训练完放几天再回来做预测只要加载这个文件列顺序永远和训练时保持一致。参数说明如果 fillna(0) 之后 isna().sum() 仍然大于 0说明有列的 dtype 是 object 但填充的是数字需要回到 2.2 的编码逻辑检查是否把全部 object 列都过了一遍。提示特征清单一定要落盘保存。常见情况是有人把 feature_cols 写在内存变量里重启内核后丢失预测时只能靠回忆补列结果一整排特征全部错位F1 直接掉十几个点。2.4 归一化staler 只允许 fit 训练集逻辑回归、SVM 这类基于距离的模型必须做归一化随机森林可以不归一化但统一做也没坏处。关键在于 scaler 只能 fit 训练集。曾经有人在拼接后的全量数据上做标准化测试集的信息提前进入训练流程评估结果虚高论文数据被导师一句“数据泄漏”打回重做。from sklearn.preprocessing import StandardScaler scaler StandardScaler() X_train scaler.fit_transform(X_train_raw) X_test scaler.transform(X_test_raw) y_train train[label].values y_test test[label].values print(X_train:, X_train.shape, X_test:, X_test.shape)逻辑说明fit_transform 在训练集上计算均值和标准差transform 在测试集上只做标准化不重新计算。这一步保证了测试集信息完全不进入训练流程也是后面所有评估结果可信的前提。参数说明如果后面要用随机森林可以保留一份未归一化的 X_train_raw 做对照树模型通常不受归一化影响但为了评估流程统一这里直接全部走同一套预处理避免“为什么两个模型输入不同”的额外解释。3. 算法选型与最小训练脚本从逻辑回归到随机森林的对照实验毕设里算法部分的典型写法是“两个以上算法做对比一张表格加一张折线图”。常见选型是逻辑回归当基线、随机森林当主力、XGBoost 当提分项。这一章先讲清楚选型逻辑再给一份能直接跑通的完整脚本最后给硬件耗时预期。3.1 选型逻辑三个标准决定用哪些算法选算法先看三个标准。第一能否在 10 分钟内出结果毕涉周期内反复调参是常态跑一轮要半小时的算法会拖垮节奏第二能否在答辩时讲清楚原理老师最常问的就是“为什么用这个算法它为什么有效”第三能否输出可视化结果。同时满足这三个条件的经典组合就是逻辑回归、随机森林、XGBoost。逻辑回归是 baseline结果再差也是个参照系随机森林是主力参数可解释性强特征重要性直接出图XGBoost 是提分项同一份数据上通常比随机森林高 1 到 3 个百分点。SVM 不建议在 17.5 万条样本上用训练时间是非线性增长效果还不一定超过随机森林性价比太低。3.2 最小训练脚本能直接跑通的对照实验下面这份脚本把训练、计时、评估封装成一个函数三个算法统一入口。跑完会打印每个模型的训练耗时和完整分类报告这些内容可以直接整理进论文的实验章节。import time from sklearn.linear_model import LogisticRegression from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report def train_and_eval(name, model): start time.time() model.fit(X_train, y_train) elapsed time.time() - start y_pred model.predict(X_test) print(f\n {name} | 训练耗时 {elapsed:.1f} 秒 ) print(classification_report(y_test, y_pred, digits3)) return model models { LogisticRegression: LogisticRegression(max_iter500, C1.0, n_jobs-1), RandomForest: RandomForestClassifier( n_estimators100, max_depth20, min_samples_leaf5, n_jobs-1, random_state42 ), } results {} for name, model in models.items(): results[name] train_and_eval(name, model)逻辑说明train_and_eval 统一封装训练、计时、评估三件事。classification_report 一次输出精确率、召回率、F1够论文表格直接用。训练耗时打印出来写进“实验环境与耗时对比”一节是评审喜欢看到的细节。参数说明LogisticRegression 的 max_iter500 保证收敛如果输出警告说未收敛继续加大到 1000C1.0 是默认正则强度调小会更强调防过拟合。RandomForest 的 max_depth20 是刻意限制避免在 17.5 万样本上无限制生长导致过拟合和内存暴涨min_samples_leaf5 让叶子节点至少 5 个样本降低方差random_state42 固定随机种子结果可复现。3.3 加上 XGBoost 提分以及硬件预期XGBoost 是大多数毕设项目里实际效果最好的单个模型前提是没调坏参数。tree_methodhist 用直方图近似在大样本上比默认的精确贪心算法快很多8GB 内存笔记本就能跑。from xgboost import XGBClassifier xgb_model XGBClassifier( n_estimators300, max_depth5, learning_rate0.1, subsample0.8, colsample_bytree0.8, tree_methodhist, eval_metriclogloss, verbosity0 ) xgb_model train_and_eval(XGBoost, xgb_model)逻辑说明subsample 和 colsample_bytree 都设 0.8每次建树只用 80% 的样本和 80% 的特征是 XGBoost 最常用的防过拟合组合。verbosity0 关掉训练日志输出清爽。参数说明n_estimators300 配合 learning_rate0.1如果想更稳把 n_estimators 加到 500、learning_rate 降到 0.05训练时间会翻倍但通常 F1 还能再涨一点。eval_metriclogloss 是二分类场景的默认评估指标这里不参与训练只用于内部日志监控。算法预期训练耗时普通笔记本预期 F1 区间定位逻辑回归1 分钟以内0.72-0.80基线对照随机森林5-10 分钟0.86-0.91毕设主力XGBoost5-15 分钟0.88-0.93提分项这张表是经验区间不是承诺。具体数值取决于预处理细节有人字符编码顺序处理不同随机森林直接差三个点。所以先跑通流程再对照区间看自己落在哪里偏低就回去查预处理。4. 模型评估与调参准确率、F1、混淆矩阵的搭配用法classification_report 打印完就收工的做法太糙。UNSW-NB15 的攻击类别分布很不均匀Generic 和 Exploits 样本多Worms、Analysis、Shellcode 样本少。只看准确率小类别全分错也可能有 85% 以上的分数这数字在论文里站不住脚。4.1 准确率会骗人优先看 F1 和召回率二分类场景里准确率高往往只是因为多数类被分对了。UNSW-NB15 训练集里攻击样本比正常流量多比例大约 1.3 比 1。如果模型把攻击类分对、正常流量误报严重准确率依然好看但实际检测系统的可用性很差。所以评估顺序应该是 F1、召回率最后才是准确率。from sklearn.metrics import precision_recall_fscore_support y_pred results[RandomForest].predict(X_test) p, r, f1, _ precision_recall_fscore_support(y_test, y_pred, averagebinary) print(f精确率: {p:.4f} | 召回率: {r:.4f} | F1: {f1:.4f})逻辑说明averagebinary 以 1攻击为正类报告的是攻击类的精确率、召回率和 F1。这组数放进论文表格配合准确率一起看才不会被一句“准确率虚高”问住。参数说明随机森林在这个数据上的 F1 通常会落在 0.85 到 0.91 区间低于这个区间先查预处理高于不必惊喜说明特征工程和调参到位了。4.2 混淆矩阵定位哪类攻击被漏掉混淆矩阵是答辩图上最直观的东西。除了 Normal 和 Attack 的二分类矩阵还可以进一步用 attack_cat 列做十类别分析。这里先给出二分类版本代码同样适用多分类。import matplotlib matplotlib.use(Agg) import matplotlib.pyplot as plt from sklearn.metrics import ConfusionMatrixDisplay disp ConfusionMatrixDisplay.from_predictions( y_test, y_pred, display_labels[Normal, Attack], normalizetrue, cmapBlues ) plt.savefig(cm.png, dpi150, bbox_inchestight)逻辑说明normalizetrue 按行归一化每个格子的数字表示该真实类别的样本有多少比例被分到了这个格子比纯计数更容易看出漏检率。savefig 直接输出 PNG论文插图不用截屏。参数说明Agg 后端适合无图形界面的服务器环境如果本地有桌面窗口可以把 savefig 换成 plt.show()但保存图片这一行建议保留后面改图方便。4.3 GridSearchCV 调参小网格、子样本避免一夜跑不完网格搜索是毕设调参的标准动作但直接在 17.5 万行全量数据上做三折交叉验证非常慢。常见做法是从训练集抽 3 万条做快速搜索定下关键参数后再用全量数据训练最终模型效率和效果兼顾。import numpy as np from sklearn.model_selection import GridSearchCV rng np.random.default_rng(42) idx rng.choice(len(X_train), size30000, replaceFalse) X_sub, y_sub X_train[idx], y_train[idx] param_grid { max_depth: [15, 20, 25], min_samples_leaf: [2, 5, 10], } gs GridSearchCV( RandomForestClassifier(n_estimators100, n_jobs-1, random_state42), param_grid, cv3, scoringf1, n_jobs-1 ) gs.fit(X_sub, y_sub) print(最优参数:, gs.best_params_, 最优 F1:, round(gs.best_score_, 4))逻辑说明3 万条子样本、3×3 的网格、3 折交叉验证组合起来几分钟出结果。拿到 best_params_ 后再用全量训练集按最优参数重训一次就是最终模型。参数说明scoringf1 让搜索以 F1 为标准而不是准确率理由见 4.1。cv3 在 3 万样本上开销可控如果只有双核 CPUn_jobs-1 反而可能拖慢整体改成 1 或 2 更稳定。5. 实战避坑用 UNSW-NB15 训练检测模型的 5 个常见问题这一章都是血泪经验。每一条按现象、原因、解决的顺序写照这个思路排查能省下大半天调试时间。这里的每个问题都在真实环境中出现过不是理论推演。5.1 训练集 F1 很高测试集掉到 0.7 附近现象是随机森林在训练集上评估 F1 接近 0.99换到测试集直接跌到 0.7甚至不同 random_state 跑出的结果波动明显。原因是过拟合叠加数据集分布差异。随机森林不限制深度时会在 17.5 万样本里逐点记忆噪声而 UNSW-NB15 的训练集和测试集来自不同流量时间段分布本身有差异训练集上习得的规律在测试集上不能完全成立。解决方法是把 max_depth 限制在 15 到 25加上 min_samples_leaf 不小于 5同时用交叉验证替代单次划分估计真实水平。如果掉点仍然严重回到 2.4 检查 scaler 是否在拼接数据上 fit 过测试集信息一旦提前泄漏测试集表现就会虚高换到真实场景立刻原形毕露。# 如果测试集 F1 偏低先改这里再重跑 RandomForestClassifier( n_estimators100, max_depth20, min_samples_leaf10, n_jobs-1, random_state42 )5.2 直接 fit 报错 could not convert string to float现象是代码在 model.fit(X_train, y_train) 处报 ValueError提示某个字段无法转换成 float。最常见原因是 id、srcip、proto 这些列没被剔除也没编码数据里混着字符串sklearn 无法解析。这个报错信息比较直白但很多人第一反应是去查数据格式而不是查特征列是否干净。解决方法是强制走特征白名单feature_cols [c for c in train.columns if c not in drop_cols [attack_cat, label]]再确认所有 object 列都过了一遍 LabelEncoder。排查时打印 X_train.dtypes只要还有 object 类型就回到 2.2 补编码。# 排查确认训练矩阵里没有 object 列 print(X_train.dtypes.value_counts()) # 如果 object 数量大于 0说明有字符列漏编码5.3 预测时提示特征名不匹配现象是 predict 时出现 sklearn 警告说训练时有 45 个特征而预测时有 43 个或者 Feature names mismatch 的提示。原因是训练和预测走了两条预处理路径列顺序发生了变化。典型场景是把预处理脚本复制了一份后来在训练脚本里加了 fillna预测脚本里没加或者反过来。解决方法是预测端加载第 2.3 节存下来的 feature_order.pkl把测试特征按这个顺序重排X_test_reordered X_test_raw[feature_order]。再走同一套编码器和 scaler 完成变换这样无论预处理顺序怎么改送入模型的列始终和训练时一致。import joblib feature_order joblib.load(feature_order.pkl) X_pred_raw X_pred_raw[feature_order] # 列顺序强制对齐 X_pred scaler.transform(X_pred_raw.fillna(0))5.4 Worms、Shellcode、Analysis 的召回率接近 0现象是 classification_report 里这三个类别 F1 只有 0.0x甚至全部被识别成其他攻击或正常流量。原因是类别严重不平衡这三个攻击类别在数据集中样本量极少模型学到的主要是 Fuzzers、Generic、Exploits 这些大类的规律小类别几乎没有机会被正确分类。解决方法是二分类时给模型加 class_weightbalanced让少数类在损失函数里获得更高权重。做多分类时对 Worms、Shellcode 等小类做上采样或者直接在论文结论里如实写“样本量过小的攻击类型识别效果有限”。诚实写结论比硬调参更有说服力评审反而认可你对数据局限性的判断。RandomForestClassifier( n_estimators100, max_depth20, class_weightbalanced, n_jobs-1, random_state42 )5.5 训练时内存占满或进程被杀现象是跑 RandomForest 时内存飙到 10GB 以上训练中断严重时直接死机。原因是两个叠加树不加深度限制且全量数据参与。随机森林默认建树到纯节点每棵树都要保存大量中间索引175341×45 的矩阵本身不大但树的递归结构非常吃内存。解决方法是限制 max_depth 和 min_samples_leafn_estimators 先给 50 做验证。如果机器只有 4GB 内存先把训练数据采样到 8 万条跑通流程再上全量。内存不足不是代码错误是资源配置问题调整参数就能解决。# 低内存机器可以先这样跑通 X_sample, y_sample X_train[:80000], y_train[:80000] RandomForestClassifier( n_estimators50, max_depth15, min_samples_leaf10, n_jobs2, random_state42 ).fit(X_sample, y_sample)6. 进阶技巧从二分类扩展到逐类别攻击识别6.1 把 label 换成 attack_cat 做 10 分类二分类只能回答“是不是攻击”但论文里往往需要回答“是哪类攻击”。把训练目标从 y_train 换成 train[attack_cat]预处理代码完全不用动随机森林一样能训。唯一要处理的是 attack_cat 里的字符串先做一套独立的 LabelEncoder。from sklearn.preprocessing import LabelEncoder le_cat LabelEncoder() y_train_cat le_cat.fit_transform(train[attack_cat]) y_test_cat le_cat.transform(test[attack_cat]) model_cat RandomForestClassifier( n_estimators200, max_depth20, min_samples_leaf5, n_jobs-1, random_state42 ) model_cat.fit(X_train, y_train_cat) print(classification_report(y_test_cat, model_cat.predict(X_test), target_namesle_cat.classes_))参数说明le_cat 必须在训练集 fit、测试集 transform新类别出现时检查 classes_。评估输出带上 target_names混淆矩阵标签就不再是一堆数字。6.2 看特征重要性给论文加一张关键图随机森林的 feature_importances_ 直接输出每个特征对分类的贡献。训练完取出 Top 20 特征画条形图并顺手用这 20 个特征重训一个模型通常准确率掉不到 1%但训练时间再降一大截。这一步能把随机森林从黑匣子变成可解释的模型。import pandas as pd imp pd.Series(model.feature_importances_, indexfeature_cols) imp.sort_values(ascendingFalse).head(20).plot.bar(figsize(10, 6)) plt.title(Top-20 Feature Importance) plt.tight_layout() plt.savefig(feature_importance.png, dpi150)这段代码直接出图配合一段“哪些特征对攻击检测贡献最大”的文字就是论文里很扎实的一节。我的习惯是训练后必看特征重要性既能发现无效列也能在答辩时讲清楚模型在关注什么。6.3 用概率阈值控制误报生产场景里误报比漏报更难处理。sklearn 默认以 0.5 作为判定阈值但对不平衡数据可以把阈值抬到 0.6 或 0.7让模型只在把握较大时报出攻击。验证方法直接加载测试集算 predict_proba 的概率列扫一遍阈值画一条误报率随阈值变化的曲线选业务可接受的点。proba model.predict_proba(X_test)[:, 1] for thr in [0.5, 0.6, 0.7, 0.8]: thr_pred (proba thr).astype(int) f1 precision_recall_fscore_support(y_test, thr_pred, averagebinary)[2] print(f阈值 {thr}: F1{f1:.4f})这个小实验做完结论页里就能写出“在误报率不超过 X% 的前提下最优阈值是 Y”比单纯汇报准确率有说服力得多。整个项目到这里就是从数据、模型到阈值决策的完整闭环。做毕设时留好每一步中间产物——特征清单、编码器、scaler、模型文件和阈值曲线——后面改任何一版都能快速回溯这是我从多次返工里养成的习惯。希望帮到你。本文还有配套的精品资源点击获取