尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

基于UNSW-NB15数据集的网络攻击检测机器学习实战:从数据预处理到Flask接口部署

发布时间:2026/9/29 14:08:22

资讯中心
01
ARTICLE

基于UNSW-NB15数据集的网络攻击检测机器学习实战:从数据预处理到Flask接口部署

基于UNSW-NB15数据集的网络攻击检测机器学习实战:从数据预处理到Flask接口部署
简介这份资源面向计算机、人工智能、通信工程等专业的在校学生与教师提供一套基于 UNSW-NB15 数据集检测网络攻击的机器学习完整方案可用于毕业设计、课程设计或大作业。压缩包共 4 个文件包含 3 个 Python 脚本与 1 个 Markdown 说明文档整体约 12KB体积轻巧、部署简单运行前阅读说明文档即可快速上手。脚本分别实现了决策树二分类器、逻辑回归二分类与 KNN 分类器覆盖从数据加载、特征处理到模型训练与攻击检测的完整流程便于对比不同算法在入侵检测任务上的表现。目前已有 143 人学习关注代码均经测试运行成功可直接用于答辩演示或作为项目初期原型。读者既能获得可复用的分类模型实现也能在此基础上修改扩展完成多分类、特征工程优化或换用其他数据集等进阶任务适合作为入门机器学习安全方向的实践参考。1. 从 UNSW-NB15 到可运行系统网络攻击检测毕设到底在做什么很多同学拿到「使用 UNSW-NB15 数据集检测网络攻击的机器学习算法」这个题目时第一反应是打开搜索引擎找现成源码然后发现要么跑不起来要么代码里全是硬编码路径要么模型训练完不知道该怎么用。这个题目的本质不是让你从零发明一个算法而是让你用公开数据集走完一条完整的机器学习流水线数据加载、特征工程、模型训练、评估、推理接口。它解决的核心问题是——给定一条网络流量记录判断它是正常流量还是某种攻击类型。适合的人群很明确计算机、网络安全、电子信息方向的本科或研究生正在做毕业设计或课程设计需要一套能演示、能答辩、能写进论文的实验系统。UNSW-NB15 本身是网络入侵检测领域常用的基准数据集包含九类攻击流量和正常流量特征维度适中不像 KDD99 那么陈旧也不像 CIC-IDS 那么庞大对单机实验非常友好。我见过太多人卡在环境配置和数据预处理上其实真正跑通之后你会发现核心代码量并不大难的是把每一步的参数和边界条件讲清楚。2. UNSW-NB15 数据集的加载与特征处理从 CSV 到模型可吃的矩阵2.1 数据集文件结构与字段含义UNSW-NB15 的原始发布形式通常包含四个 CSV 文件训练集和测试集各一个外加特征列表和类别标签说明。训练集和测试集已经按时间或随机方式切分好了你不需要自己再做 train_test_split这一点对毕设很友好因为可以直接引用官方划分来证明实验的规范性。每个 CSV 文件里每一行代表一条网络流记录列包含约四十多个特征大致分为以下几类流特征如源 IP、目的 IP、源端口、目的端口、协议、时间特征如流持续时间、到达间隔、统计特征如源到目的字节数、目的到源包数、内容特征如 HTTP 方法、DNS 查询。最后一列通常是attack_cat或labellabel是二分类标签0 正常1 攻击attack_cat是多分类标签Normal、Generic、Exploits、Fuzzers、DoS、Reconnaissance、Analysis、Backdoor、Shellcode、Worms。我一般会先写一段脚本把列名和数据类型打印出来确认哪些是数值型、哪些是分类型。常见做法是用 pandas 读入后直接看dtypes和head()。这里有一个容易翻车的点原始 CSV 里有些列可能被 pandas 解析成 object 类型比如proto、service、state这些是分类型特征需要做编码。另外attack_cat列在测试集里可能包含训练集没出现过的攻击子类如果你做多分类要提前检查类别对齐问题。import pandas as pd import numpy as np # 加载训练集和测试集注意文件路径按实际存放位置修改 train_df pd.read_csv(UNSW_NB15_training-set.csv) test_df pd.read_csv(UNSW_NB15_testing-set.csv) # 查看基本信息 print(训练集形状:, train_df.shape) print(测试集形状:, test_df.shape) print(列名:, train_df.columns.tolist()) print(数据类型分布:) print(train_df.dtypes.value_counts()) # 检查标签分布 print(二分类标签分布:) print(train_df[label].value_counts()) print(多分类标签分布:) print(train_df[attack_cat].value_counts())这段代码的作用是快速摸清数据全貌。参数方面pd.read_csv默认用逗号分隔如果文件里有特殊编码可能需要加encodingutf-8或encodinglatin-1。value_counts()能帮你判断类别是否平衡——UNSW-NB15 本身是不平衡的正常流量远多于某些攻击类型这会影响后续模型评估指标的选择。2.2 分类型特征编码与数值标准化分类型特征不能直接喂给大多数机器学习模型需要转成数值。常见做法有两种Label Encoding 和 One-Hot Encoding。对于proto、service、state这种取值有限的列我一般用 One-Hot因为类别之间没有顺序关系。但要注意One-Hot 之后特征维度会膨胀如果训练集和测试集的类别不一致会导致列对不齐。稳妥的做法是先把训练集和测试集合并做统一的 One-Hot然后再拆开。数值型特征如dur、sbytes、dbytes的量纲差异很大标准化或归一化能加速收敛尤其是用 SVM、KNN 或神经网络时。树模型如随机森林、XGBoost 对量纲不敏感但标准化也不会带来坏处。from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.compose import ColumnTransformer from sklearn.pipeline import Pipeline # 分离特征和标签 X_train train_df.drop([label, attack_cat], axis1) y_train train_df[label] X_test test_df.drop([label, attack_cat], axis1) y_test test_df[label] # 找出分类型列和数值型列 cat_cols X_train.select_dtypes(include[object]).columns.tolist() num_cols X_train.select_dtypes(include[np.number]).columns.tolist() print(分类型列:, cat_cols) print(数值型列数量:, len(num_cols)) # 构建预处理管道 preprocessor ColumnTransformer( transformers[ (num, StandardScaler(), num_cols), (cat, OneHotEncoder(handle_unknownignore), cat_cols) ]) # 在训练集上拟合在测试集上转换 X_train_processed preprocessor.fit_transform(X_train) X_test_processed preprocessor.transform(X_test) print(处理后训练集形状:, X_train_processed.shape) print(处理后测试集形状:, X_test_processed.shape)这里的关键参数是handle_unknownignore它保证测试集里出现训练集没见过的类别时不会报错而是将该类别对应的所有 One-Hot 列置为 0。ColumnTransformer的好处是能把不同列的预处理逻辑封装在一起避免手动拼接出错。注意fit_transform只在训练集上调用测试集只能用transform否则会造成数据泄露这是毕设答辩时老师常问的点。2.3 特征选择去掉冗余列提升训练效率UNSW-NB15 里有些列对分类贡献很小比如id列如果存在就是纯索引必须删掉。还有一些列之间高度相关比如sbytes和dbytes在某些攻击类型下相关性很高。我一般会先看方差再看过拟合风险。常见做法是用随机森林的feature_importances_或者用SelectKBest做初步筛选。但毕设里不建议过度删特征因为特征工程本身也是工作量保留合理数量的特征并解释清楚为什么保留比盲目删到只剩几个更有说服力。from sklearn.ensemble import RandomForestClassifier import matplotlib.pyplot as plt # 用随机森林快速评估特征重要性 rf RandomForestClassifier(n_estimators100, random_state42, n_jobs-1) rf.fit(X_train_processed, y_train) # 获取特征重要性注意 One-Hot 后特征名会变多 importances rf.feature_importances_ indices np.argsort(importances)[::-1] # 打印前 20 个重要特征 print(前 20 个重要特征的重要性分数:) for i in range(20): print(f{i1}. 特征索引 {indices[i]}: {importances[indices[i]]:.4f})这段代码训练一个随机森林并输出特征重要性排序。n_estimators100是常用起点n_jobs-1表示用满所有 CPU 核心加速。注意经过 One-Hot 后特征索引和原始列名不再一一对应如果你想在论文里写「哪些原始特征最重要」需要额外做映射。一个实用技巧是在ColumnTransformer之后用get_feature_names_out()获取处理后的特征名再和重要性对应起来。3. 模型选型与训练从逻辑回归到 XGBoost 的对比实验3.1 为什么选树模型作为基线网络攻击检测本质上是一个分类问题但数据有几个特点类别不平衡、特征维度中等、部分特征存在非线性关系。逻辑回归简单可解释但对非线性边界拟合能力有限SVM 在小样本上表现好但 UNSW-NB15 训练集有十几万条核函数计算开销大朴素贝叶斯假设特征独立实际网络流量特征之间相关性明显效果通常一般。相比之下基于树的集成方法——随机森林、XGBoost、LightGBM——能自动处理非线性关系对类别不平衡有一定鲁棒性还能输出特征重要性非常适合毕设场景。我一般会选随机森林作为基线再用 XGBoost 做提升两者对比能体现工作量。from sklearn.ensemble import RandomForestClassifier from xgboost import XGBClassifier from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, classification_report import time # 随机森林训练与评估 rf_model RandomForestClassifier( n_estimators200, max_depth20, min_samples_split5, random_state42, n_jobs-1 ) start time.time() rf_model.fit(X_train_processed, y_train) rf_train_time time.time() - start y_pred_rf rf_model.predict(X_test_processed) print(随机森林结果:) print(f训练耗时: {rf_train_time:.2f} 秒) print(f准确率: {accuracy_score(y_test, y_pred_rf):.4f}) print(f精确率: {precision_score(y_test, y_pred_rf):.4f}) print(f召回率: {recall_score(y_test, y_pred_rf):.4f}) print(fF1 分数: {f1_score(y_test, y_pred_rf):.4f}) print(classification_report(y_test, y_pred_rf))参数说明n_estimators200表示 200 棵树树越多效果越稳定但训练越慢max_depth20控制树的最大深度防止过拟合min_samples_split5表示节点最少 5 个样本才继续分裂。这些参数没有绝对最优值需要根据你的机器性能和实验结果调整。classification_report会输出每个类别的精确率、召回率和 F1对于不平衡数据F1 比准确率更有参考价值。3.2 XGBoost 的参数调优与早停策略XGBoost 在结构化数据上通常比随机森林更强但参数更多调不好反而翻车。核心参数有n_estimators树的数量、max_depth树深、learning_rate学习率、subsample行采样比例、colsample_bytree列采样比例、scale_pos_weight正负样本权重比。对于不平衡数据scale_pos_weight可以设为负样本数除以正样本数让模型更关注少数类。早停策略用early_stopping_rounds在验证集上监控指标如果连续若干轮不提升就停止训练避免过拟合和浪费时间。from xgboost import XGBClassifier from sklearn.model_selection import train_test_split # 从训练集里再切一部分做验证集用于早停 X_tr, X_val, y_tr, y_val train_test_split( X_train_processed, y_train, test_size0.1, random_state42, stratifyy_train ) # 计算正负样本比例 scale (y_tr 0).sum() / (y_tr 1).sum() xgb_model XGBClassifier( n_estimators500, max_depth8, learning_rate0.05, subsample0.8, colsample_bytree0.8, scale_pos_weightscale, eval_metriclogloss, early_stopping_rounds30, random_state42, n_jobs-1 ) xgb_model.fit( X_tr, y_tr, eval_set[(X_val, y_val)], verbose50 ) y_pred_xgb xgb_model.predict(X_test_processed) print(XGBoost 结果:) print(f最佳迭代轮数: {xgb_model.best_iteration}) print(f准确率: {accuracy_score(y_test, y_pred_xgb):.4f}) print(fF1 分数: {f1_score(y_test, y_pred_xgb):.4f}) print(classification_report(y_test, y_pred_xgb))eval_set传入验证集verbose50表示每 50 轮打印一次日志。early_stopping_rounds30意味着如果验证集损失连续 30 轮不下降就停止。best_iteration告诉你实际用了多少棵树。注意早停需要验证集所以从训练集里再切一部分出来不要用测试集做早停否则测试集就失去了评估意义。3.3 多分类扩展识别具体攻击类型二分类只能告诉你「是不是攻击」但毕设往往要求识别「哪种攻击」。UNSW-NB15 的attack_cat列提供了多分类标签。多分类的做法和二分类类似只是把标签换成attack_cat模型输出改为多类别。XGBoost 和随机森林都支持多分类但要注意类别不平衡在多分类里更严重某些攻击类型样本极少模型可能完全学不到。常见处理方式是合并稀有类别或者用类别权重。评估时不能只看整体准确率要看每个类别的 F1 和混淆矩阵。from sklearn.preprocessing import LabelEncoder # 多分类标签编码 le LabelEncoder() y_train_multi le.fit_transform(train_df[attack_cat]) y_test_multi le.transform(test_df[attack_cat]) print(类别映射:, dict(zip(le.classes_, le.transform(le.classes_)))) # 用随机森林做多分类 rf_multi RandomForestClassifier( n_estimators200, max_depth20, class_weightbalanced, random_state42, n_jobs-1 ) rf_multi.fit(X_train_processed, y_train_multi) y_pred_multi rf_multi.predict(X_test_processed) print(多分类结果:) print(classification_report(y_test_multi, y_pred_multi, target_namesle.classes_))class_weightbalanced会自动根据类别频率调整权重缓解不平衡问题。target_names让报告可读性更好。如果某些类别 F1 为 0说明样本太少或特征区分度不够可以考虑合并到相近类别或者在论文里说明该类别检测困难的原因。4. 避坑与排查UNSW-NB15 实验中最容易翻车的五个地方4.1 现象模型准确率 99% 但召回率极低原因数据严重不平衡正常流量占绝大多数模型学会了「全部预测为正常」也能拿到高准确率。解决不要用准确率作为唯一指标改用 F1、AUC 或召回率。同时设置class_weightbalanced或scale_pos_weight让模型关注少数类。如果还是不行考虑对少数类过采样或对多数类欠采样但要注意过采样可能造成过拟合。4.2 现象测试集准确率远低于训练集原因过拟合。可能是树太深、特征太多、训练轮数太多。解决降低max_depth增加min_samples_split使用早停或者增加正则化参数如reg_alpha、reg_lambda。另外检查是否有数据泄露比如标准化时用了全部数据而不是只在训练集上拟合。4.3 现象One-Hot 后训练集和测试集列数不一致原因训练集和测试集的分类型特征取值不完全相同分别做 One-Hot 会导致列对不齐。解决合并后再做 One-Hot或者用handle_unknownignore让编码器忽略未知类别。更稳妥的做法是用ColumnTransformer在训练集上拟合然后直接转换测试集。4.4 现象XGBoost 训练报错「early_stopping_rounds requires eval_set」原因没有传验证集。解决从训练集里切一部分作为验证集通过eval_set参数传入。注意验证集不能和测试集混用否则评估结果不可信。4.5 现象多分类时某些类别完全预测不出来原因样本太少模型没有足够信息学习。解决检查类别分布如果某个类别样本少于 100 条考虑合并到相似类别或者在论文里单独讨论。也可以尝试用 SMOTE 对少数类过采样但要注意 SMOTE 对高维稀疏数据效果可能不稳定。5. 从实验到演示用 Flask 搭一个可交互的检测接口5.1 模型持久化与加载训练完的模型需要保存下来否则每次演示都要重新训练。常见做法是用joblib或pickle保存模型和预处理器。注意预处理器和模型必须一起保存因为推理时需要对输入做同样的转换。import joblib # 保存模型和预处理器 joblib.dump(rf_model, rf_model.pkl) joblib.dump(preprocessor, preprocessor.pkl) # 加载 loaded_model joblib.load(rf_model.pkl) loaded_preprocessor joblib.load(preprocessor.pkl) # 模拟一条新流量记录 sample X_test.iloc[0:1] sample_processed loaded_preprocessor.transform(sample) prediction loaded_model.predict(sample_processed) print(预测结果:, prediction)joblib对 numpy 数组的序列化效率比 pickle 高适合保存 sklearn 模型。保存后的文件可以随源码一起打包部署时直接加载。5.2 Flask 接口编写与请求测试Flask 是最轻量的 Web 框架适合毕设演示。核心思路是提供一个 POST 接口接收 JSON 格式的流量特征返回预测结果。注意输入特征需要和训练时的列顺序一致分类型字段要转成字符串。from flask import Flask, request, jsonify import joblib import pandas as pd app Flask(__name__) model joblib.load(rf_model.pkl) preprocessor joblib.load(preprocessor.pkl) app.route(/predict, methods[POST]) def predict(): data request.get_json() df pd.DataFrame([data]) processed preprocessor.transform(df) pred model.predict(processed)[0] prob model.predict_proba(processed)[0].max() return jsonify({ prediction: int(pred), confidence: float(prob), label: 攻击 if pred 1 else 正常 }) if __name__ __main__: app.run(host0.0.0.0, port5000, debugFalse)启动后用 curl 或 Postman 测试curl -X POST http://127.0.0.1:5000/predict \ -H Content-Type: application/json \ -d {dur:0.1,proto:tcp,service:http,state:FIN,sbytes:100,dbytes:200}注意实际输入需要包含所有训练时用到的列缺失列会导致转换失败。debugFalse在生产环境更安全但调试时可以设为True看详细错误。5.3 一个容易被忽略的细节输入特征顺序Flask 接口接收的 JSON 字典在转 DataFrame 时列顺序可能和训练时不一致。ColumnTransformer内部是按列名匹配的所以只要列名对得上就没问题。但如果你的预处理器是用位置索引而不是列名就会翻车。我一般会在训练时记录feature_names_in_推理时按这个顺序重排。另外分类型字段如果传了训练时没见过的值handle_unknownignore会把它当成全零向量不会报错但可能影响精度。5.4 演示系统的打包与运行说明毕设提交时老师通常希望拿到就能跑。我一般会把代码整理成以下结构data/放数据集model/放保存的模型文件app.py是 Flask 入口train.py是训练脚本requirements.txt列出依赖。运行步骤写在 README 里先pip install -r requirements.txt再python train.py训练模型最后python app.py启动服务。注意数据集文件通常较大如果平台有大小限制可以只放测试集或提供下载说明。模型文件如果太大可以用joblib.dump(..., compress3)压缩。# requirements.txt 示例 pandas2.0.3 numpy1.24.3 scikit-learn1.3.0 xgboost1.7.6 flask2.3.2 joblib1.3.1版本号不是固定的但建议锁定大版本避免因为库升级导致 API 不兼容。如果老师环境里没有 GPUXGBoost 用 CPU 版本即可n_jobs-1已经能利用多核。5.5 从毕设到可展示成果的最后一步很多人代码跑通了但答辩时讲不清楚。我的习惯是准备一张流程图数据加载 → 预处理 → 特征选择 → 模型训练 → 评估 → 接口部署。每个环节准备一句话说明为什么这么做。另外把混淆矩阵和特征重要性图保存下来答辩时直接展示。如果时间允许可以做一个简单的 HTML 页面用 fetch 调用 Flask 接口输入几个特征就能看到预测结果演示效果比命令行好得多。最后记得在论文里写清楚实验环境Python 版本、主要库版本、CPU 型号、训练耗时这些细节能让你的实验更可信。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。