XGBoost 实现网络入侵数据的检测(二)

                      单位:东北大学   作者:王文举

      网络入侵检测方法,是通过收集网络流量或主机流量的信息并进行分析的一种技术方法 。通过xgboost学习方法可以有效地判断当前网络是否异常,提升校检的精度。
     采用的是 NSL-KDD 数据集,数据集是 KDD Cup 99 的改进版数据集,消除了 KDD Cup 99 数据集中冗余的数据。此外,也对数据集类别标签比例进行调整改进,避免样本类别分布不均匀现象。
本文XGBoost原理理论的部分不在过多叙述,具体可参考链接:
https://blog.csdn.net/weixin_43214046/article/details/106993291

0.数据样本介绍

     KDD Cup 1999数据集: 是与KDD-99第五届数据挖掘国际竞赛使用的数据集。任务是建立一个网络入侵检测器,这是一种能够区分称为入侵或攻击的“不良”连接和“良好”的正常连接的预测模型。
     训练数据集有 125973 行数据,测试数据集有 22544 行数据,每个数据集都有 42 列特征维度,最后一列是标记特征(Label),其他前41项特征共分为四大类。
  TCP连接基本特征(共9种,序号1~9)
  TCP连接的内容特征(共13种,序号10~22)
  基于时间的网络流量统计特征 (共9种,序号23~31)
  基于主机的网络流量统计特征 (共10种,序号32~41)
  其样本特征见下表:
0,tcp,http,SF,239,486,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,8,8,0.00,0.00,0.00,0.00,1.00,0.00,0.00,19,19,1.00,0.00,0.05,0.00,0.00,0.00,0.00,0.00,normal.
  下图为读取后的特征数据,每个特征取值空间和类型属性不在叙述:
在这里插入图片描述

1.NSL-KDD数据预处理

     由于XGBoost所采用的弱评估器为CART决策树,故需要将特征空间的字符型进行映射操作,使其转换数据的形式。常见的数据预处理的操作大致可以包括以下几点:
   (0)类别标签不均衡处理:
类别不均衡指不同的类别的训练样例数目有较大的差异。假定正例偏少,负例偏多的情况下,有效地采用3种解决方法。
(a):过采样。增加正例的数据使得正反例数目大致接近。如果对正例进行重复采样操作,会造成过拟合现象,常见的方法大多为插值采样。
(b):欠采样。减少负例的数据使得正反例数目大致接近,采样可能会造成重要特征丢失,一般用于集成学习算法中。
©:再缩放操作。文中二分类采用binary:logistic 为损失函数。当前仅当预测值y满足:
y1y>m+m \frac{y}{1-y}>\frac{m^+}{m^-}才可以预测为正例。

   (1)特征选择:
XGBoost采用随机森林的思想,选取部分特征,采用多线程并行处理方式,计算每个特征划分下,以结构分数分差的最大值为依据,选取特征分裂。
   (2)数据稀疏和缺失值处理
对于特征值有缺失的样本,xgboost可以自动学习它的分裂方向。在决策树中,一般统计在缺失特征下,每个取值所占据整个样本空间的比例,并根据比例将该样本划分不同的权重。
   (3)字符型进行映射操作
一般看字符型特征是否有序,有序采用LabelEncoder编码映射。本文中udp、tpc、http均为无序,采用OneHotEncoder编码。
   (4)PCA降维技术
特征空间较小不做 pca 降维技术。
   (5)数据标准化/归一化处理
决策树、朴素贝叶斯、XGBoost均为类条件概率模型,不做标准化归一化处理。

2.SKlearn API 接口使用

(0)导库:

from sklearn.metrics import accuracy_score
from xgboost import XGBClassifier as XGBC
from sklearn.model_selection import KFold, cross_val_score as CVS, train_test_split as TTS
from sklearn.metrics import mean_squared_error as MSE
import pandas as pd
from sklearn.metrics import r2_score,mean_squared_error as MSE
from sklearn.model_selection import learning_curve
import numpy as np
import matplotlib.pyplot as plt
from time import time
import datetime
import pickle

(0)读数据并保存数据:

'''
    # KDDtrain_data = pd.read_csv("xgboost\\DATA\\KDDTrain+.txt" ,
    #                             names = list(range(43)), header=0)
    # pickle.dump(KDDtrain_data, open("KDDtrain_data.dat","wb"))
    #
    # KDDTest = pd.read_csv("xgboost\\DATA\\KDDTest+.txt",
    #                       names=list(range(43)), header=0 )
    # pickle.dump(KDDTest, open("KDDTest.dat","wb"))
    # 加载文件
    '''

(1)数据预处理:

def processdata(data):
    sp = [] #记录哪些时是字符型的列
    for col in range(41):
         if data[col].dtypes == data[41].dtypes:
            sp.append(col)
            le = LabelEncoder()
            le.fit(data[col])
            data[col] = le.transform(data[col])
            # one-code编码  max(data[2])
            df_processed = pd.get_dummies(data[col],prefix_sep="_")
            # 转化后的属性
            df_processed.columns = [str(col)+'.' + str(int(i))  \
            for i in range(df_processed.shape[1])]
            data = pd.concat([data, df_processed], axis=1)
    #实现标签二分类处理,存储标签
    data[41] = np.where(data[41] == 'normal', 1, 0)
    label = data[41]
    # 去除替换后的字符型数据,同时把网络受攻击程度42列去掉,
    # 得到样本特征空间
    data = data.drop(data.columns[sp+[41,42]], axis=1)  # axis=1,试图指定列
    datas = pd.concat([data, label], axis=1)
    return datas

(2)走XGBoost流程:

 # xt, yt, x_test, y_test分别表示训练集、训练集标签、测试集、测试标签
def ytest(xt, yt, x_test, y_test):
    time0 = time()
    xgbt = XGBC(n_estimators=150,
                subsample=0.8,
                learning_rate=0.5,
                random_state=20,
                gamma=0.25,
                reg_lambda=10,
                max_depth = 4,
                object = 'binary:logistic',
                min_child_weight=2,
                seed= 0,
                booster='gbtree')
    y_predict = xgbt.fit(xt, yt).predict(x_test)
    x_predict = xgbt.fit(xt, yt).predict(xt)
    print('训练集 :',accuracy_score(x_predict,yt))
    print('测试集 :',accuracy_score(y_predict, y_test))
    print('测试r2指标 :',r2_score(y_predict, y_test))
    print('测试MSE指标 :',MSE(y_predict, y_test))
    print('运行时间 :',time() - time0)

(3)经验设置调参,先跑一遍看看结果:
在这里插入图片描述
选择经验参数,训练测试的准确率均达到99.9%以上,但测试集R2R^2偏低。

3.调参

(1)训练集样本大小影响:
将上述训练集进行5折交叉验证(45\frac{4}{5}用于训练,15\frac{1}{5}用于验证),将每轮验证的结果求均值,这样就返回不同样本参数下的模型的Score。这里的Score就是上述说的指标R2R^2

def sample_influence(xt,yt):
    # 训练集样本的大小影响
    cv = KFold(n_splits=5, shuffle=True, random_state=42)  # 交叉验证模式
    plot_learning_curve(XGBC(n_estimators=100, random_state=42), \
                        "XGBC", xt, yt, ax=None, cv=cv)
    plt.show()
def plot_learning_curve(estimator, title, X, y,
                        ax=None,  # 选择子图
                        ylim=None,  # 设置纵座标的取值范围
                        cv=None,  # 交叉验证
                        n_jobs=None  # 设定索要使用的线程
                        ):
    train_sizes, train_scores, test_scores = learning_curve(estimator, X, y
                                                , shuffle=True
                                                , cv=cv
                                                , random_state=420
                                                , n_jobs=n_jobs)
    if ax == None:
        ax = plt.gca()
    else:
        ax = plt.figure()
    ax.set_title(title)
    if ylim is not None:
        ax.set_ylim(*ylim)
    ax.set_xlabel("Training examples")
    ax.set_ylabel("Score")
    ax.plot(train_sizes, np.mean(train_scores, axis=1), 'o-'
            , color="r", label="Training score")
    ax.plot(train_sizes, np.mean(test_scores, axis=1), 'o-'
            , color="g", label="Test score")
    ax.legend(loc="best")
    return ax

结果:
在这里插入图片描述
(2)基学习器个数(n_estimators):

def ntrees_estimators(Xtrain,Ytrain):
    cv = KFold(n_splits=5, shuffle=True, random_state=42)  # 交叉验证模式
    axisx = range(50, 400,50)
    rs = []
    var = []
    ge = []
    for i in axisx:
        print(i)
        reg = XGBC(n_estimators=i, random_state=420,
                   subsample=0.8,
                   learning_rate=0.2)
        cvresult = CVS(reg, Xtrain, Ytrain, cv=cv)
        rs.append(cvresult.mean())
        var.append(cvresult.var())
        ge.append((1 - cvresult.mean()) ** 2 + cvresult.var())
    print(axisx[rs.index(max(rs))], max(rs), var[rs.index(max(rs))])
    print(axisx[var.index(min(var))], rs[var.index(min(var))], min(var))
    print(axisx[ge.index(min(ge))], rs[ge.index(min(ge))], var[ge.index(min(ge))], min(ge))
    rs = np.array(rs)
    var = np.array(var)
    plt.plot(axisx, rs, c="black", label="XGB")
    # 添加方差线
    plt.plot(axisx, rs + var, c="red", linestyle='-.')
    plt.plot(axisx, rs - var, c="red", linestyle='-.')
    plt.legend()
    plt.show()

评估器大范围调节在【50,400】每50取值,下图可见在150附近最好。R2R^2均在99.8%以上
在这里插入图片描述
同理,确定最大树的深度max_depth参数优化如下图:
在这里插入图片描述同理,惩罚项gamma参数优化如下图:
在这里插入图片描述

4.评价指标

代码主程序:

if __name__ == '__main__':
	    KDDtrain_data = pickle.load(open("KDDtrain_data.dat", "rb"))
	    KDDTest = pickle.load(open("KDDTest.dat", "rb"))
	    dataxtrain = processdata(KDDtrain_data)
	    dataxtext = processdata(KDDTest)
	    # 训练集、测试集划分
	    xt, yt, x_test, y_test = dataxtrain.iloc[:, 0:41], \
	    dataxtrain.iloc[:, 41], dataxtext.iloc[:, 0:41], dataxtext.iloc[:, 41]
	    # sample_influence(xt, yt)
	    # ntrees_estimators(xt,yt)   #弱学习器的个数
	    # gamasolve(xt,yt)
	    ytest(xt, yt, x_test, y_test)

XGBoost经调参后,R2R^2,MSE有明显的提升。R2R^2从0.42提升至0.64,MSE从原先0.0005降低到0.00022,准确率提升至接近4个9。
在这里插入图片描述
模型的特征重要性:
在这里插入图片描述
ROC曲线绘制
代码:

    y_score =  xgbt.fit(xt, yt).predict_proba(x_test)
    fpr,tpr,threshold=roc_curve(y_test,y_score[:, 1])
    roc_auc=auc(fpr,tpr)
    plt.figure(figsize=(10,10))
    plt.plot(fpr, tpr, color='darkorange',
    lw=2, label='ROC curve (area = %0.2f)' % roc_auc) ###假正率为横座标,真正率为纵座标做曲线
    plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
    plt.xlim([0.0, 1.0])
    plt.ylim([0.0, 1.05])
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')
    plt.title('Receiver operating characteristic example')
    plt.legend(loc="lower right")
    plt.show()

运行结果:

在这里插入图片描述
说明:文中具体的代码上传至Github,欢迎查看。
链接: https://github.com/WANGWENJUS/xgboost.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章