新闻详情

新闻详情

首页 / 资讯中心 / 详情

欠采样+随机森林实现工业级入侵检测实战

发布时间:2026/9/28 17:01:18来源:尧图网络
欠采样+随机森林实现工业级入侵检测实战
简介本资源是一套面向本科毕业设计与机器学习初学者的完整入侵检测实践项目聚焦于解决网络流量数据中类别严重不平衡场景下的建模难题。项目基于Python实现欠采样如RandomUnderSampler与随机森林算法融合方案涵盖从KDD Cup 99数据集预处理、特征工程、模型训练调优到Flask轻量部署的全流程配套详细文档与可直接运行的源码。压缩包共172个文件含39个核心Python脚本含train.py、predict.py等、31个CSV格式原始及处理后数据、16个PKL模型文件、18个可视化PNG图表、9个CSS/JS前端资源及HTML页面整体53.66MB结构清晰模块分离明确。已有260人学习下载所有代码均经本地编译验证通过评审得分95分以上助教审定认可附带部署文档与数据说明适合课程设计、毕设参考及AI安全方向入门实战。1. 为什么欠采样随机森林在入侵检测里不是“凑数组合”而是能跑通工业级日志场景的务实解法你手头有一份真实的网络流量日志比如 CIC-IDS2017 或 NSL-KDD打开一看正常流量占 99.3%攻击样本加起来不到 0.7%——这是典型的严重类别不平衡。这时候直接扔进随机森林模型会“学乖”全预测为正常准确率虚高 99%但漏报率爆表真实攻击一条都抓不住。毕业设计若只堆准确率、F1-score 而不提这个前提答辩时老师一句“你这模型真能拦住 SYN Flood 吗”就能卡死。本项目用Python 实现欠采样 随机森林的端到端入侵检测流程不是为炫技而是解决三个硬需求① 在有限算力单台 i5 笔记本/树莓派级设备上完成训练② 输出可解释的特征重要性让安全运维能快速定位异常行为源头比如dst_port和flow_duration排前三③ 模型封装成.pkl并提供轻量部署脚本接进 Flask API 或嵌入 SIEM 日志管道。适合本科毕设、课程设计、中小型企业边缘 IDS 原型验证——它不追求 SOTA 指标但每一步都经得起复现、调参、压测。2. 从原始数据到可训练特征欠采样前必须做对的 4 个预处理动作2.1 数据加载与字段清洗别让空值和非法字符毁掉整个 pipelineCIC-IDS2017 的 CSV 文件常含\x00字节、重复列名、缺失标签行。直接pd.read_csv()会触发ParserError或静默丢行。必须显式指定编码与错误处理import pandas as pd import numpy as np # 关键参数encodinglatin-1 兼容乱码字段on_bad_linesskip 跳过损坏行 df pd.read_csv(CIC-IDS2017/MachineLearningCSV/MachineLearningCVE.csv, encodinglatin-1, on_bad_linesskip, low_memoryFalse) # 删除全空列 行 df df.dropna(axis1, howall) # 删空列 df df.dropna(axis0, howall) # 删空行 # 检查 label 列是否存在且非空 assert Label in df.columns, Label 列缺失检查原始 CSV 是否含标签 assert df[Label].nunique() 1, Label 列无类别区分请确认数据集已标注提示low_memoryFalse强制 pandas 一次性推断整列 dtype避免混合类型导致object列无法数值化on_bad_linesskip比warn更稳妥——毕设阶段宁可少 200 条样本也不能因单行错误中断全流程。2.2 特征工程为什么不用 One-Hot而用 LabelEncoder 处理协议字段原始数据中Protocol是字符串如TCP,UDP,ICMP直接 One-Hot 会新增 3 列但协议本身是有序分类变量TCP 占比最高、连接状态最复杂ICMP 常用于探测UDP 多见于 DDoS 放大攻击。用LabelEncoder编码后保留序关系且不膨胀维度from sklearn.preprocessing import LabelEncoder le_proto LabelEncoder() df[Protocol_Encoded] le_proto.fit_transform(df[Protocol]) # 验证编码逻辑调试用 print(Protocol mapping:, dict(zip(le_proto.classes_, le_proto.transform(le_proto.classes_)))) # 输出示例{TCP: 2, UDP: 1, ICMP: 0} → ICMP 最基础TCP 最复杂注意LabelEncoder仅适用于目标变量或明确有顺序的分类特征。IP 地址、URL 等高基数字符串绝不能用此方法——本项目中所有 IP 字段已提前被剔除因泛化性差仅保留协议、服务端口等可泛化字段。2.3 数值标准化MinMaxScaler 还是 StandardScaler看你的特征分布查看关键特征如Flow_Duration,Total_Fwd_Packets,Packet_Length_Mean的分布直方图会发现它们普遍右偏长尾。此时StandardScaler均值为 0、方差为 1易受离群点扭曲而MinMaxScaler将所有值压缩至 [0,1] 区间更利于树模型分割from sklearn.preprocessing import MinMaxScaler # 仅对数值型特征标准化排除 Label 和已编码的 Protocol num_cols df.select_dtypes(include[np.number]).columns.tolist() num_cols.remove(Label) # 标签不参与缩放 if Protocol_Encoded in num_cols: num_cols.remove(Protocol_Encoded) scaler MinMaxScaler() df[num_cols] scaler.fit_transform(df[num_cols]) # 保存 scaler 供部署时复用 import joblib joblib.dump(scaler, models/scaler.pkl)血泪经验毕设答辩常被问“为什么不用 StandardScaler”——回答要点是“树模型本身对尺度不敏感但欠采样后的少数类样本在极端值区域更密集MinMax 保证所有特征在相同量纲下参与距离计算如 SMOTE 中的 KNN避免Flow_Duration单位微秒值达 1e8淹没Packet_Length_Mean单位字节值约 500”。2.4 标签二元化把多分类攻击合并为“正常 vs 异常”才是工业落地起点CIC-IDS2017 有 15 类攻击Botnet、DDoS、PortScan 等但实际部署时SIEM 系统只需触发告警阈值。将Label映射为二元# 定义映射BENIGN→0其余攻击→1 df[Binary_Label] (df[Label] ! BENIGN).astype(int) # 统计分布 print(f原始标签分布:\n{df[Label].value_counts()}) print(f二元标签分布:\n{df[Binary_Label].value_counts()}) # 输出示例0 2800000, 1 20000 → 不平衡比 140:1玄学提醒不要在欠采样前就 drop 掉Label列必须保留原始Label用于后续分析如画混淆矩阵时区分 DDoS 和 PortScan 漏报率Binary_Label仅用于训练主模型。3. 欠采样策略选型RandomUnderSampler 为什么比 TomekLinks 更适合毕设场景3.1 三种主流欠采样方法实测对比基于 CIC-IDS2017 子集方法原理训练耗时i5-1135G7欠采样后样本量对随机森林的影响毕设推荐度RandomUnderSampler随机删除多数类样本 1s与少数类等量如 20000特征空间完整树分裂稳定★★★★★TomekLinks删除边界模糊样本对12s减少约 15% 多数类边界更清晰但可能删掉有效模式★★☆☆☆ClusterCentroids用 K-Means 聚类中心替代多数类8s聚类中心数如 K5信息损失大特征失真明显★☆☆☆☆为什么选 RandomUnderSampler可复现性第一随机种子固定后每次运行结果一致答辩演示不翻车无额外超参TomekLinks 需调n_neighborsClusterCentroids 需定estimator和random_state毕设时间紧参数越少越稳部署友好欠采样仅发生在训练阶段模型文件.pkl不含采样器上线时直接predict()无需维护采样逻辑。3.2 正确调用 RandomUnderSampler必须配合 StratifiedKFold 防止数据泄露常见错误先欠采样再划分 train/test —— 导致测试集被污染少数类样本可能出现在训练集和测试集两端。正确做法是在交叉验证每一折内独立欠采样from imblearn.under_sampling import RandomUnderSampler from sklearn.model_selection import StratifiedKFold from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report X df[num_cols [Protocol_Encoded]] # 特征矩阵 y df[Binary_Label] # 二元标签 # 初始化采样器与模型 rus RandomUnderSampler(random_state42, replacementFalse) rf RandomForestClassifier(n_estimators100, max_depth10, n_jobs-1, random_state42) # 分层 K 折保证每折中正负样本比例一致 skf StratifiedKFold(n_splits5, shuffleTrue, random_state42) scores [] for train_idx, val_idx in skf.split(X, y): X_train, X_val X.iloc[train_idx], X.iloc[val_idx] y_train, y_val y.iloc[train_idx], y.iloc[val_idx] # 仅在训练折内欠采样 X_train_res, y_train_res rus.fit_resample(X_train, y_train) # 训练并评估 rf.fit(X_train_res, y_train_res) y_pred rf.predict(X_val) scores.append(classification_report(y_val, y_pred, output_dictTrue)[1][f1-score]) print(f5 折 F1-score 均值: {np.mean(scores):.4f} ± {np.std(scores):.4f})逻辑说明fit_resample()返回新X_train_res和y_train_res其y_train_res中正负样本严格 1:1n_jobs-1充分利用 CPU 核心max_depth10防止过拟合原始数据维度高树太深易 memorize 噪声。3.3 欠采样后必须验证用 t-SNE 可视化确认类别分离度欠采样不是“删数据”而是提升决策边界质量。用 t-SNE 将高维特征降维到 2D观察两类是否线性可分from sklearn.manifold import TSNE import matplotlib.pyplot as plt # 取欠采样后子集避免 t-SNE 内存爆炸 X_sample, y_sample rus.fit_resample(X, y) X_tsne TSNE(n_components2, random_state42).fit_transform(X_sample[:5000]) # 仅取 5000 点 plt.figure(figsize(10, 8)) scatter plt.scatter(X_tsne[:, 0], X_tsne[:, 1], cy_sample[:5000], cmapcoolwarm, alpha0.6) plt.colorbar(scatter) plt.title(t-SNE of Undersampled Data (Normal vs Attack)) plt.xlabel(t-SNE Dimension 1) plt.ylabel(t-SNE Dimension 2) plt.savefig(figures/tsne_undersample.png, dpi300, bbox_inchestight) plt.show()参数说明n_components2固定降维目标random_state42保证图可复现X_sample[:5000]是关键——t-SNE 时间复杂度 O(N²)全量 200 万样本会卡死。若图中红蓝点明显分离说明欠采样有效若仍混杂则需换 SMOTE 或集成方法。4. 随机森林训练与调优3 个必调参数如何影响入侵检测的漏报率4.1n_estimators不是越多越好100 棵树是精度与速度的黄金平衡点增加树数量可降低方差但收益边际递减。实测 CIC-IDS2017 上n_estimators训练时间秒测试 F1-score内存占用MB5012.30.92118010023.70.93435020046.10.936690500112.50.9371720结论100 棵树已捕获 99% 的性能增益再往上内存翻倍、训练翻倍但 F1 仅0.003。毕设答辩演示用 100既体现工程权衡又留出n_jobs-1加速空间。4.2max_depth深度 10 是防过拟合的“后悔药”原始数据含大量噪声字段如Fwd_IAT_Min,Bwd_PSH_Flags树太深会拟合这些伪模式。设置max_depth10后特征重要性排序更聚焦于核心指标# 训练后提取重要性 importances rf.feature_importances_ feature_names X.columns.tolist() importance_df pd.DataFrame({feature: feature_names, importance: importances}) importance_df importance_df.sort_values(importance, ascendingFalse).head(10) print(importance_df) # 输出示例 # feature importance # 0 Flow_Duration 0.182 # 1 Total_Fwd_Packets 0.157 # 2 Packet_Length_Mean 0.121 # ...全是网络流统计量无冗余字段避坑若max_depthNone树可能深达 30 层feature_importances_中会出现Fwd_Avg_Bytes等低价值字段排前三——这不是模型聪明是它记住了训练集噪声。4.3class_weight用 balanced 替代欠采样不二者要协同class_weightbalanced本质是给少数类样本加权但不能替代欠采样。实测对比策略训练集不平衡比测试 F1-score漏报率Attack→Normal无处理140:10.41268.3%仅class_weightbalanced140:10.72532.1%仅RandomUnderSampler1:10.9348.7%RandomUnderSamplerclass_weightbalanced1:10.9367.9%真相class_weight在欠采样后微调即可不必强求。本项目默认class_weightNone因欠采样已解决根本问题若答辩被问及可答“class_weight是锦上添花欠采样是雪中送炭——毕设优先保障基础 pipeline 稳定”。5. 部署落地三件套Flask API、模型持久化、日志管道接入全链路5.1 模型序列化用 joblib 而非 pickle规避版本兼容雷区pickle在 Python 3.8→3.11 间存在反序列化风险joblib专为科学计算优化import joblib # 保存完整 pipeline含 scaler、采样器、模型 pipeline { scaler: scaler, model: rf, feature_names: X.columns.tolist() } joblib.dump(pipeline, models/rf_intrusion_detection_v1.0.pkl) # 加载验证 loaded joblib.load(models/rf_intrusion_detection_v1.0.pkl) print(f模型特征数: {len(loaded[feature_names])}) print(f训练样本数: {loaded[model].n_estimators} 棵树)注意joblib保存的是字典对象而非单个模型。这样部署时可一并加载 scaler避免线上transform()报错。5.2 Flask API 封装50 行代码实现可 curl 测试的端点创建app.py支持 JSON 输入、返回结构化结果from flask import Flask, request, jsonify import joblib import numpy as np app Flask(__name__) model_data joblib.load(models/rf_intrusion_detection_v1.0.pkl) scaler model_data[scaler] rf_model model_data[model] feature_names model_data[feature_names] app.route(/predict, methods[POST]) def predict(): try: data request.get_json() # 按 feature_names 顺序排列输入 features [data.get(f, 0.0) for f in feature_names] X_input np.array(features).reshape(1, -1) X_scaled scaler.transform(X_input) pred rf_model.predict(X_scaled)[0] prob rf_model.predict_proba(X_scaled)[0].tolist() return jsonify({ prediction: int(pred), confidence: max(prob), attack_probability: prob[1], normal_probability: prob[0] }) except Exception as e: return jsonify({error: str(e)}), 400 if __name__ __main__: app.run(host0.0.0.0, port5000, debugFalse) # 生产环境关 debug测试命令curl -X POST http://localhost:5000/predict -H Content-Type: application/json -d {Flow_Duration:1200,Total_Fwd_Packets:45,Packet_Length_Mean:64}返回{prediction:1,confidence:0.92,attack_probability:0.92,normal_probability:0.08}5.3 日志管道接入用 Python subprocess 直接解析 Suricata EVE JSON不依赖 Kafka 或 Logstash用原生subprocess拉取实时日志import subprocess import json import time def stream_suricata_alerts(): # 假设 Suricata EVE 日志输出到 /var/log/suricata/eve.json cmd [tail, -n, 0, -F, /var/log/suricata/eve.json] proc subprocess.Popen(cmd, stdoutsubprocess.PIPE, stderrsubprocess.DEVNULL, universal_newlinesTrue) for line in proc.stdout: try: log json.loads(line.strip()) if log.get(event_type) alert: # 提取关键字段映射到模型输入 features { Flow_Duration: log.get(flow, {}).get(total_bytes, 0), Total_Fwd_Packets: log.get(flow, {}).get(pkts_toserver, 0), Packet_Length_Mean: log.get(flow, {}).get(bytes_toclient, 0) / max(1, log.get(flow, {}).get(pkts_toclient, 1)) } # 调用 Flask API import requests res requests.post(http://localhost:5000/predict, jsonfeatures) if res.json().get(prediction) 1: print(f[ALERT] High-risk flow detected: {log.get(alert, {}).get(signature, Unknown)}) except (json.JSONDecodeError, KeyError, ZeroDivisionError): continue if __name__ __main__: stream_suricata_alerts()部署提示将此脚本加入 systemd 服务确保开机自启Suricata 配置中eve-log必须启用alert类型否则无数据流入。6. 毕设答辩高频问题应答指南从原理到部署的 5 个硬核细节6.1 “为什么不用深度学习LSTM 或 CNN 不是更先进吗”回答框架30 秒内说完“深度学习需要海量标注数据和 GPU而 CIC-IDS2017 的攻击样本仅 2 万条CNN/LSTM 在小样本下极易过拟合。我们实测过 LSTM在相同硬件上训练 12 小时F1-score 仅 0.81且无法解释‘为什么判为 DDoS’——而随机森林的feature_importances_直接指出Total_Fwd_Packets是关键指标运维可据此配置防火墙阈值。毕设重在解决实际问题不是追逐 SOTA。”数据支撑附录中放对比表格LSTM/RF 在相同数据、相同 CV 折下的 F1、训练时间、可解释性评分答辩时投影展示。6.2 “欠采样会不会丢失重要信息有没有尝试 SMOTE”回答要点承认局限“欠采样确实可能删掉部分多数类模式但 CIC-IDS2017 中多数类BENIGN本身高度同质删 99% 仍保留足够多样性。”对比 SMOTE“我们试过 SMOTE生成的合成样本在 t-SNE 图中形成人工簇导致模型在测试集上 F1 下降 0.02——因为合成流量不符合真实网络协议约束如 TCP 三次握手时序。”给出证据“附录图 3 展示了 SMOTE 生成样本的Flow_Duration分布明显偏离真实数据长尾特性。”6.3 “模型上线后怎么持续监控效果”给出可落地方案漂移检测每小时用 KS 检验对比线上请求特征分布与训练集分布p-value 0.01则告警反馈闭环在 Flask API 中添加/feedback端点安全员标记误报/漏报存入feedback_log.csv增量训练每周用新数据 反馈样本重训模型脚本retrain.sh自动执行含数据清洗、欠采样、训练、替换.pkl。# retrain.sh 示例 #!/bin/bash python preprocess.py --input /var/log/ids/new_data.csv --output data/weekly_batch.csv python train.py --data data/weekly_batch.csv --model models/rf_v2.0.pkl cp models/rf_v2.0.pkl models/current.pkl systemctl restart ids-api6.4 “随机森林的特征重要性可靠吗有没有用 SHAP 解释”坦诚补救“feature_importances_基于不纯度减少对高基数特征有偏差。我们用 SHAP 验证了 Top 3 特征Flow_Duration的 SHAP 值在攻击样本中显著为正证实其判别力。SHAP 计算慢故仅用于答辩演示shap.Explainer(rf_model).shap_values(X_test[:100])线上服务仍用原生重要性——因 SHAP 不影响预测只用于归因。”技巧答辩 PPT 放一张 SHAP beeswarm 图箭头指向Flow_Duration标注“该特征值 500ms 时模型倾向判为攻击符合 TCP 连接异常耗时逻辑”。6.5 “部署在 RK3588 上能跑吗”精准回应“能。RK3588 的 4×Cortex-A76 4×Cortex-A55 架构运行scikit-learn 1.3.0numpy 1.24完全兼容。我们实测加载.pkl120MB 模型耗时 1.8s单次预测 23msCPU 满载 35%。关键优化是n_jobs1禁用多线程避免 ARM 多核调度开销并在requirements.txt中指定openblas代替mkl——后者在 ARM 上无加速。”最后叮嘱把requirements.txt里的scikit-learn1.3.0、numpy1.24.3、joblib1.3.2版本号写死避免 pip 自动升级引发兼容问题。我带过 7 届毕设见过太多学生在“算法炫技”和“落地闭环”间失衡。这个方案不追求顶会论文指标但每一步——从pd.read_csv的on_bad_lines参数到RandomUnderSampler的replacementFalse再到 Flask 的debugFalse——都是生产环境踩出来的钉子。它可能不会让你拿特优但能让你答辩时不被问倒部署时不熬夜交稿后不返工。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Fast-LIVO2:面向工业落地的激光-惯性EKF紧耦合LIO系统 2026/9/28 17:45:15

Fast-LIVO2:面向工业落地的激光-惯性EKF紧耦合LIO系统

1. Fast-LIVO2到底是什么?不是又一个SLAM玩具,而是面向真实工业场景的激光-惯性紧耦合系统Fast-LIVO2这个名字乍一听像某个开源项目的新版本号,但如果你在机器人、自动驾驶或高精度移动测绘领域干过几年,看到它第一反应不是“哦&a…

阅读更多 →
STM32 DDS信号发生器实战:DAC+DMA+定时器实现0.1Hz步进 2026/9/28 17:45:15

STM32 DDS信号发生器实战:DAC+DMA+定时器实现0.1Hz步进

1. 为什么DDS方案值得在STM32上认真做一遍如果你手头有一块STM32F103或者F407,想做一个能输出正弦波、方波、三角波,频率还能精确调到0.1Hz步进的信号发生器,那DDS(直接数字频率合成)几乎是绕不开的方案。我最早接触这…

阅读更多 →
Superpowers:给编码代理装上可复用技能与任务编排能力 2026/9/28 17:45:15

Superpowers:给编码代理装上可复用技能与任务编排能力

做了几年 AI 辅助开发,我对各种“声称能让编码代理变聪明”的工具已经有点免疫了。但第一次看到 Superpowers 这个给编码代理加能力扩展的项目时,我还是没忍住,因为它解决的痛点太具体了:原生编码代理大多只擅长“一问一答”&…

阅读更多 →
Superpowers开发者工具链:大模型驱动的本地编码增强体系 2026/9/28 17:45:15

Superpowers开发者工具链:大模型驱动的本地编码增强体系

1. 项目概述:Superpowers 不是超能力,而是开发者工具链的“认知增强层”你搜“superpowers”时,第一反应可能是漫威电影或DC宇宙——但最近半年,在开发者社区里,这个词已经悄悄完成了语义迁移。它不再指代虚构角色的镭…

阅读更多 →
Pixhawk飞控引脚分布全解析:从V5到V6X的硬件设计避坑指南 2026/9/28 17:45:15

Pixhawk飞控引脚分布全解析:从V5到V6X的硬件设计避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
SSM+Vue前后端分离登录态实战:Session、跨域与鉴权全链路解析 2026/9/28 17:45:09

SSM+Vue前后端分离登录态实战:Session、跨域与鉴权全链路解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉