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.

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