單位:東北大學 作者:王文舉
網絡入侵檢測方法,是通過收集網絡流量或主機流量的信息並進行分析的一種技術方法 。通過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滿足:
纔可以預測爲正例。
(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%以上,但測試集偏低。
3.調參
(1)訓練集樣本大小影響:
將上述訓練集進行5折交叉驗證(用於訓練,用於驗證),將每輪驗證的結果求均值,這樣就返回不同樣本參數下的模型的Score。這裏的Score就是上述說的指標。
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附近最好。均在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經調參後,,MSE有明顯的提升。從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.