基于机器学习的网络入侵检测与特征选择及随机森林分类器性能评估(NSL-KDD数据集)

简介

本文将详细介绍如何利用Python和相关机器学习库对NSL-KDD数据集进行预处理,特征选择,并通过随机森林算法构建网络入侵检测模型。同时,还将展示如何计算并可视化模型的ROC曲线以评估其性能。

首先,我们导入了必要的库,如pandas、seaborn、numpy以及scikit-learn等,并加载了KDDTrain+和KDDTest+两个数据集。通过对数据集进行初步探索,我们将列名重置为实际含义,并将标签(attack_type)以及其他类别型特征进行了编码转换。

在特征工程阶段,我们分析了攻击类型特征的相关性,通过找出与攻击类型关联最小的10个特征以及标准差较小的5个特征,确定了一组待删除的冗余特征。通过剔除这些特征,我们得到了精简后的数据集combined_data_reduced,并进一步将其划分为特征矩阵X和目标向量y。

接下来,我们使用随机森林分类器作为模型,设置了参数n_estimators为10,criterion为’entropy’,max_features为’auto’,bootstrap设置为True,以便训练模型并对测试集进行预测。获取模型在测试集上的得分,并输出了特征重要性。

为了更深入地评估模型的性能,我们还绘制了ROC曲线。ROC曲线是一种用于二分类问题中直观展示模型性能的工具,它展示了假正率(False Positive Rate, FPR)与真正率(True Positive Rate, TPR)之间的权衡关系。这里我们生成了一个示例数据集,并使用同样的随机森林模型计算出其ROC曲线。最后,我们在图表中添加了“无技能”基准线(即随机猜测的结果),并与模型的实际ROC曲线进行了对比。

总结来说,本篇文章展示了从原始数据预处理到特征选择,再到建立随机森林模型并评估其性能的全过程,为我们提供了在网络入侵检测领域运用机器学习技术的一个实践案例。

步骤

  1. 数据加载与初步预处理:读取KDDTrain+和KDDTest+两个CSV文件,合并为一个数据集,并重新命名列名。
  2. 特征工程:对类别型特征如攻击类型、协议类型等进行标签编码,分析特征与目标变量之间的相关性,基于相关性和标准差筛选出最不相关的特征予以删除,优化特征空间。
  3. 数据划分:将精简后的数据集划分为特征矩阵X和目标向量y,并进一步划分为训练集和测试集。
  4. 模型建立与训练:使用随机森林分类器进行训练,设置参数优化模型性能。
  5. 模型评估:计算模型在测试集上的准确率,并提取特征重要性;此外,还通过生成二分类示例数据集,展示了模型的ROC曲线,以更全面地评估模型在区分正常流量与攻击流量时的性能。

代码实现

导入必要的库

# 配置IPython自动补全为贪心模式
%config IPCompleter.greedy=True
# 导入数据处理和可视化库
import pandas as pd
import seaborn as sns
import numpy as np
import re
import sklearn# 忽略警告信息
import warnings
warnings.filterwarnings("ignore")# 导入绘图库及其配置
import matplotlib.pyplot as plt
import matplotlib as matplot
%matplotlib inline# 设置IPython交互模式为全节点
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"# 导入数据集划分工具
from sklearn.model_selection import train_test_split

数据加载及预处理

从指定路径读取NSL-KDD99数据集的训练集和测试集;
重置训练集和测试集的列名,以便后续处理;
将训练集和测试集合并为一个大的数据集,以便进行统一的分析和处理;
调整数据集的列名,以符合特征的实际情况;
删除不需要的特征列,以简化数据集。

# 导入训练集和测试集
train = pd.read_csv('/kaggle/input/nsl-kdd99-dataset/KDDTrain+.txt')
test = pd.read_csv('/kaggle/input/nsl-kdd99-dataset/KDDTest+.txt')# 获取训练集和测试集的形状(行数和列数)
train.shape
test.shape # 重命名训练集和测试集的列,使用列的序号作为列名
train.columns = range(train.shape[1])
test.columns = range(test.shape[1])# 定义标签列表,对应数据集中的特征含义
labels = ['duration', 'protocol_type', 'service', 'flag', 'src_bytes',
'dst_bytes', 'land', 'wrong_fragment', 'urgent', 'hot',
'num_failed_logins', 'logged_in', 'num_compromised', 'root_shell',
'su_attempted', 'num_root', 'num_file_creations', 'num_shells',
'num_access_files', 'num_outbound_cmds', 'is_host_login',
'is_guest_login', 'count', 'srv_count', 'serror_rate',
'srv_serror_rate', 'rerror_rate', 'srv_rerror_rate', 'same_srv_rate',
'diff_srv_rate', 'srv_diff_host_rate', 'dst_host_count',
'dst_host_srv_count', 'dst_host_same_srv_rate', 'dst_host_diff_srv_rate', 'dst_host_same_src_port_rate',
'dst_host_srv_diff_host_rate', 'dst_host_serror_rate',
'dst_host_srv_serror_rate', 'dst_host_rerror_rate',
'dst_host_srv_rerror_rate', 'attack_type', 'difficulty_level']# subclass - > attack_type# 将训练集和测试集合并为一个数据集
combined_data = pd.concat([train, test])# 获取合并后数据集的形状
combined_data.shape# 显示合并后数据集的前5行
combined_data.head(5)# 将合并后数据集的列名替换为定义的标签列表
combined_data.columns = labels# 删除合并后数据集中的'difficulty_level'列
combined_data = combined_data.drop('difficulty_level', 1)# 显示处理后的合并数据集的前3行
combined_data.head(3)
0123456789...33343536373839404142
00udpotherSF14600000...0.000.600.880.000.000.000.00.00normal15
10tcpprivateS0000000...0.100.050.000.001.001.000.00.00neptune19
20tcphttpSF23281530000...1.000.000.030.040.030.010.00.01normal21
30tcphttpSF1994200000...1.000.000.000.000.000.000.00.00normal21
40tcpprivateREJ000000...0.070.070.000.000.000.001.01.00neptune21

5 rows × 43 columns

durationprotocol_typeserviceflagsrc_bytesdst_byteslandwrong_fragmenturgenthot...dst_host_srv_countdst_host_same_srv_ratedst_host_diff_srv_ratedst_host_same_src_port_ratedst_host_srv_diff_host_ratedst_host_serror_ratedst_host_srv_serror_ratedst_host_rerror_ratedst_host_srv_rerror_rateattack_type
00udpotherSF14600000...10.00.600.880.000.000.000.00.00normal
10tcpprivateS0000000...260.10.050.000.001.001.000.00.00neptune
20tcphttpSF23281530000...2551.00.000.030.040.030.010.00.01normal

3 rows × 42 columns

数据编码

from sklearn import preprocessing
# 导入预处理模块le = preprocessing.LabelEncoder()
# 创建标签编码器对象# 打印攻击类型集合,以查看原始值
print(set(list(combined_data['attack_type']))) # 对数据集中的'attack_type''protocol_type''service''flag'列进行标签编码
combined_data['attack_type'] = le.fit_transform(combined_data['attack_type'])
combined_data['protocol_type'] = le.fit_transform(combined_data['protocol_type'])
combined_data['service'] = le.fit_transform(combined_data['service'])
combined_data['flag'] = le.fit_transform(combined_data['flag'])# 描述编码后的攻击类型数据
print('\nDescribing attack_type: ')
print("min", combined_data['attack_type'].min()) # 最小值
print("max", combined_data['attack_type'].max()) # 最大值
print("mean", combined_data['attack_type'].mean()) # 平均值
print("mode", combined_data['attack_type'].mode()) # 模式,即出现频率最高的值
print("looks like 16 is 'normal' ")
# 根据编码结果推断,16可能代表'normal'攻击类型

特征消除和数据集分割

根据攻击类型与其他特征的相关性以及特征的标准差,进行特征选择和消除

# 计算特征之间的相关性矩阵,并按'attack_type'的绝对相关性值进行排序
corr_matrix = combined_data.corr().abs().sort_values('attack_type')# 选择与'attack_type'相关性最低的前10个特征
leastCorrelated = corr_matrix['attack_type'].nsmallest(10)
leastCorrelated = list(leastCorrelated.index)# 选择标准差最低的前5个特征
leastSTD =  combined_data.std().to_frame().nsmallest(5, columns=0)
leastSTD = list(leastSTD.transpose().columns)# 结合相关性和标准差,得到需要消除的特征集合
featureElimination = set(leastCorrelated + leastSTD)
len(featureElimination)
featureElimination# 根据特征集合,从数据集中删除选定的特征
combined_data_reduced = combined_data.drop(featureElimination,axis=1)# 分离特征和标签,并将数据集划分为训练集和测试集
data_x = combined_data_reduced.drop('attack_type', axis=1)
data_y = combined_data_reduced.loc[:,['attack_type']]
X_train, X_test, y_train, y_test = train_test_split(data_x, data_y, test_size=.5, random_state=42)  # 待完成:说明train_test_split的具体作用和参数意义

{‘dst_bytes’,
‘is_host_login’,
‘land’,
‘logged_in’,
‘num_access_files’,
‘num_compromised’,
‘num_file_creations’,
‘num_outbound_cmds’,
‘num_root’,
‘num_shells’,
‘root_shell’,
‘srv_rerror_rate’,
‘su_attempted’,
‘urgent’}

训练随机森林分类器模型

# 导入必要的库
import numpy as np
import matplotlib.pyplot as plt
from itertools import cyclefrom sklearn import svm, datasets
from sklearn.metrics import roc_curve, auc
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import label_binarize
from sklearn.multiclass import OneVsRestClassifier
from sklearn.metrics import roc_auc_score
from sklearn import metricsfrom sklearn import linear_modelfrom sklearn.ensemble import VotingClassifierfrom sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.ensemble import IsolationForestfrom sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifierimport gc 
gc.collect()# 初始化随机森林分类器
RF = RandomForestClassifier(n_estimators=10, criterion='entropy', max_features='auto', bootstrap=True)# 训练模型
RF.fit(X_train, y_train)
# 获取特征重要性
RF_feature = RF.feature_importances_# 在测试集上评估模型性能
rf_score = RF.score(X_test, y_test)
print('RandomForestClassifier processing ,,,')# 多类别问题的二进制化处理
y = preprocessing.label_binarize(y_train, classes=[0, 1, 2, 3])
n_classes = y.shape[1]# 示例:绘制预测模型的ROC曲线
# 生成二分类数据集
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_curve
from matplotlib import pyplotX, y = make_classification(n_samples=1000, n_classes=2, random_state=1)
# 划分训练集和测试集
trainX, testX, trainy, testy = train_test_split(X, y, test_size=0.5, random_state=2)
# 训练模型
model = RandomForestClassifier()
model.fit(trainX, trainy)
# 预测概率
yhat = model.predict_proba(testX)
# 获取正类的概率
pos_probs = yhat[:, 1]
# 绘制无技能的ROC曲线
pyplot.plot([0, 1], [0, 1], linestyle='--', label='No Skill')
# 计算模型的ROC曲线
fpr, tpr, _ = roc_curve(testy, pos_probs)
# 绘制模型的ROC曲线
pyplot.plot(fpr, tpr, marker='_', label='RFC_Performance')
# 添加轴标签
pyplot.xlabel('False Positive Rate')
pyplot.ylabel('True Positive Rate')
# 显示图例
pyplot.legend()
# 显示图形
pyplot.show()

在这里插入图片描述
在这里插入图片描述

优化建议

  1. 特征选择方面,可以尝试更多的特征选择方法,如递归特征消除(RFE)、基于树的特征重要性排序等,寻找最优特征子集。
  2. 超参数调优:针对随机森林分类器,可以通过网格搜索或随机搜索等方式调整n_estimators、max_depth、min_samples_split等超参数,寻找最佳模型配置。
  3. 类别不平衡问题处理:由于实际场景中正常流量可能远大于异常流量,可考虑引入过采样、欠采样或SMOTE等技术平衡各类别样本。
  4. 模型集成:结合AdaBoostClassifier、GradientBoostingClassifier等多种分类器进行集成学习,提高整体预测性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/525713.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java服务器-Disruptor使用注意

最近看了一下部署后台的服务器状况,发现我的一个Java程序其占用的CPU时长超过100%,排查后发现竟是Disruptor引起的,让我们来看看究竟为什么Disruptor会有这样的表现。 发现占用CPU时间超过100%的进程 首先是在服务器上用top命令查看服务器状…

300分钟吃透分布式缓存-23讲:Redis是如何淘汰key的?

淘汰原理 首先我们来学习 Redis 的淘汰原理。 系统线上运行中,内存总是昂贵且有限的,在数据总量远大于 Redis 可用的内存总量时,为了最大限度的提升访问性能,Redis 中只能存放最新最热的有效数据。 当 key 过期后,或…

专题一 - 双指针 - leetcode 202. 快乐数 | 简单难度

leetcode 202. 快乐数 leetcode 202. 快乐数 | 简单难度1. 题目详情1. 原题链接2. 基础框架 2. 解题思路1. 题目分析2. 算法原理3. 时间复杂度 3. 代码实现4. 知识与收获 leetcode 202. 快乐数 | 简单难度 1. 题目详情 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」…

geoserver+mapbox-gl 离线部署矢量切片地图服务学习笔记

geoserver安装 geoserver的安装包可以在官网下载Download - GeoServer,想要选择版本点击Archived找到指定版本进行下载http://geoserver.org/download/ (如果网络不稳定,也可以直接使用下面的下载地址) geoserver-2.15.0.rar资…

多线程-线程池原子性并发工具类

1.线程池 1.线程状态 虚拟机中线程的六种状态 新建状态(NEW) --创建线程 就绪状态(RUNNABLE) --start方法 阻塞状态(BLOCKED) --无法获得锁对象 等待状态(WAITING) …

观其大略之HybridCLR学习笔记

问题背景 1 现有热更方案的开发效率、性能没有到达极限,还有提升的空间 2 ios多平台政策导致热更新受限问题,ios禁止jit。根据我查找的资料,ios的代码段启动的时候就确定了,不能增加新的代码段。IOS封了内存(或者堆&…

2024软件测试工具测评,总有一款适合你!

在软件开发周期中,测试是确保产品质量的关键环节。随着企业对于软件质量的要求日益提升,测试人员面临着前所未有的挑战,“工欲善其事必先利其器”,选择一款高效、实用的软件测试工具,不仅能够提升测试效率,…

【比较mybatis、lazy、sqltoy、mybatis-flex、easy-query、mybatis-mp操作数据】操作批量新增、分页查询(四)

orm框架使用性能比较 比较mybatis、lazy、sqltoy、mybatis-flex、easy-query、mybatis-mp操作数据 环境: idea jdk17 spring boot 3.0.7 mysql 8.0测试条件常规对象 orm 框架是否支持xml是否支持 Lambda对比版本编码方式mybatis☑️☑️3.5.4lambda xml 优化sq…

嘉绩咨询:搭建品牌招商桥梁,提供卓越讲师与会议服务

当下,品牌成功的关键在于强大的渠道支撑和高效的招商能力,在这一背景下,嘉绩咨询,这一专注于渠道招商全案系统孵化的知名平台型企业,今日宣布,将进一步加强其在品牌招商桥梁搭建上的服务功能,通…

[java] 23种设计模式之桥接模式

一、什么是桥接模式 桥接(Bridge)模式属于结构型设计模式。通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。把抽象(abstraction)与行为实现(implementation)分离开来,从而可以保持各部分的独立性以及应对它们的功能扩展。 二、适用场景 当一…

不知道吧,腾讯云轻量应用服务器使用有一些限制!

腾讯云轻量应用服务器相对于云服务器CVM是有一些限制的,比如轻量服务器不支持更换内网IP地址,不支持自定义私有网络VPC,内网连通性方面也有限制,轻量不支持CPU内存、带宽或系统盘单独升级,只能整个套餐整体升级&#x…

Intellij IDEA 中 git 操作的快捷键

1.添加新建的文件 即add 操作 shift alt a 2.提交操作 即 commit操作 ctrl k 在窗口中可以用feature来声明此次更新的内容 3.提交操作 即push操作 ctrl shift k 4.拉去远程分支操作 即pull操作 ctrl t