温馨提示:文末有 CSDN 平台官方提供的学长 QQ 名片 :)
网络流量分类或网络流量异常检测,采用基于聚类的机器学习算法,实现异常检测与分类,即划分为正常流量和异常流量。 数据集来源自 KDD CUP,该数据集是从一个模拟的美国空军局域网上采集来的 9 个星期的网络连接数据, 分成具有标识的训练数据和未加标识的测试数据。测试数据和训练数据有着不同的概率分布, 测试数据包含了一些未出现在训练数据中的攻击类型, 这使得入侵检测更具有现实性。本项目利用 pandas + Matplotlib + seaborn + sklearn 对网络流量数据进行统计分析,并构建聚类算法实现对流量的分类建模。
基于聚类方法的网络流量分类的主要功能包括:
- import warnings
- warnings.filterwarnings('ignore')
- import os
- import gc
- import numpy as np
- import pandas as pd
- import seaborn as sns
- import matplotlib as mpl
- import matplotlib.pyplot as plt
- from IPython.display import display
- np.random.seed(7)
- plt.style.use('seaborn')
- from tqdm import tqdm
- import requests
- from bs4 import BeautifulSoup
- import json
- import time
利用 pandas 完成数据集的读取,并将 attack_ type 进行类型转换:
- data_df = pd.read_csv('data/kddcup.data_10_percent', sep=',', error_bad_lines=False, header=None)
-
- def transform_target(attack_type):
- attack_type = attack_type[:-1]
- if attack_type == 'normal':
- return attack_type
- elif attack_type not in {'smurf', 'neptune'}:
- return 'attack'
- else:
- return 'None'
-
- data_df['attack_type'] = data_df['attack_type'].map(transform_target)
- data_df = data_df[data_df['attack_type'] != 'None']
duration | protocol_type | service | flag | src_bytes | dst_bytes | land | wrong_fragment | urgent | hot | ... | 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 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
34669 | 0 | tcp | http | SF | 276 | 2729 | 0 | 0 | 0 | 0 | ... | 255 | 1.00 | 0.00 | 0.25 | 0.01 | 0.0 | 0.0 | 0.0 | 0.0 | normal |
146619 | 2472 | udp | other | SF | 147 | 105 | 0 | 0 | 0 | 0 | ... | 1 | 0.00 | 0.87 | 0.98 | 0.00 | 0.0 | 0.0 | 0.0 | 0.0 | normal |
29842 | 0 | tcp | http | SF | 219 | 1434 | 0 | 0 | 0 | 0 | ... | 255 | 1.00 | 0.00 | 0.00 | 0.00 | 0.0 | 0.0 | 0.0 | 0.0 | normal |
136719 | 0 | tcp | http | SF | 327 | 274 | 0 | 0 | 0 | 0 | ... | 224 | 0.88 | 0.02 | 0.00 | 0.00 | 0.0 | 0.0 | 0.0 | 0.0 | normal |
23970 | 0 | tcp | http | SF | 217 | 626 | 0 | 0 | 0 | 0 | ... | 255 | 1.00 | 0.00 | 0.00 | 0.00 | 0.0 | 0.0 | 0.0 | 0.0 | normal |
由于数据集太大,我们根据数据类型将数据集分为三部分(object、integer、float)并进行分析。在41个固定的特征属性中,9个特征属性为离散型,其他均为连续型。通过对41个固定特征属性的分析,比较能体现出状态变化的是前31个特征属性,其中9个离散型,22个连续型。因此对连接记录的分析处理是针对该31个特征属性。接下来将这31个特征属性进行总结分析。
可以看出,有97277个正常样本,8752个攻击样本,占8.2%,标注样本极不平衡,攻击类型的样本太少,为验证聚类模型的效果,考虑将其合并为一种其他攻击类型。
特征工程之前,先查看各列或特征在数据集中的不同值的个数,以梳理哪些是数值类型哪些是类别类型的特征。
- # 查看各列或特征在数据集中的不同值的个数
- for column in data_df.columns:
- print(len(set(data_df[column])), ':', column)
聚类算法中要使用计算距离的方法对数据进行聚类, 而连接记录的固定特征属性中有两种类型的数值: 离散型和连续型。 对于连续型特征属性, 各属性的度量方法不一样。
针对类别型特征,进行 LabelEncoder 编码:
- from sklearn import preprocessing
-
- le = preprocessing.LabelEncoder()
-
- # 字符串类型的特征进行 LabelEncode 编码
- data_df['protocol_type'] = le.fit_transform(data_df['protocol_type'])
- data_df['service'] = le.fit_transform(data_df['service'])
- data_df['flag'] = le.fit_transform(data_df['flag'])
-
- data_df['attack_type'] = data_df['attack_type'].map(lambda x: int(x == 'attack'))
-
- target = data_df['attack_type']
- del data_df['attack_type']
数据的量纲不同,数量级差别很大,经过标准化处理后,原始数据转化为无量纲化指标测评值,各指标值处于同一数量级别,可进行综合测评分析。
如果直接用原始指标值进行分析,就会突出数值较高的指标在综合分析中的作用,相对削弱数值水平较低指标的作用。
- # 最大值-最小值归一化
- scaler = preprocessing.MinMaxScaler()
-
- data_df = scaler.fit_transform(data_df)
- plt.figure(figsize=(20, 8))
- plt.scatter(data[target == 1][:, 0], data[target == 1][:, 1], label='1: attack', color='red')
- plt.scatter(data[target == 0][:, 0], data[target == 0][:, 1], label='0: normal')
- plt.legend()
- plt.show()
- from sklearn.model_selection import train_test_split
- from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
-
- # 划分测试集
- train_x, test_x, train_y, test_y, tsne_train, tsne_test = train_test_split(data_df, target.values, data, test_size=0.1, random_state=42)
- print('训练集:{}, 测试集: {}'.format(train_x.shape[0], test_x.shape[0]))
训练集:4819, 测试集: 536
- from sklearn.cluster import KMeans
-
- # 创建 KMeans 模型
- kmeans_model = KMeans(n_clusters=2, random_state=42)
-
- # 训练 kmeans 模型
- kmeans_model.fit(train_x)
-
- # 训练集预测
- pred_trains = kmeans_model.predict(train_x)
-
- # 测试集预测
- pred_tests = kmeans_model.predict(test_x)
-
- print('训练集正确率:{:f},精确率:{:f},召回率:{:f},F1-Score:{:f}'.format(
- accuracy_score(pred_trains, train_y),
- precision_score(pred_trains, train_y),
- recall_score(pred_trains, train_y),
- f1_score(pred_trains, train_y))
- )
- print('测试集正确率:{:f},精确率:{:f},召回率:{:f},F1-Score:{:f}'.format(
- accuracy_score(pred_tests, test_y),
- precision_score(pred_tests, test_y),
- recall_score(pred_tests, test_y),
- f1_score(pred_tests, test_y))
- )
- 训练集正确率:0.818220,精确率:0.539043,召回率:0.235943,F1-Score:0.328221
- 测试集正确率:0.847015,精确率:0.714286,召回率:0.339806,F1-Score:0.460526
测试集预测结果绘图:
红色的为预测错误的样本,灰色的Wie预测正确的样本,可以看出,单纯的 KMeans 模型的测试集 F1-Score 只有 0.334297,模型存在提升空间!
本项目基于随机森林算法进行特征选择:
- ......
-
- train_probs = clf.predict_proba(train_x)
- test_probs = clf.predict_proba(test_x)
-
- train_probs = np.reshape(train_probs[:, 0], (train_probs.shape[0], 1))
- test_probs = np.reshape(test_probs[:, 0], (test_probs.shape[0], 1))
-
- feature_importances = pd.DataFrame({'features': feature_names, 'important': clf.feature_importances_})
-
- feature_importances.sort_values(by='important', ascending=False)
-
- # 去掉特征主要程度低的特征
- good_features = feature_importances['features'].values[:10]
特征筛选后,重新训练 kmeans 聚类算法:
- print('训练集正确率:{:f},精确率:{:f},召回率:{:f},F1-Score:{:f}'.format(
- accuracy_score(pred_trains, train_y),
- precision_score(pred_trains, train_y),
- recall_score(pred_trains, train_y),
- f1_score(pred_trains, train_y))
- )
- print('测试集正确率:{:f},精确率:{:f},召回率:{:f},F1-Score:{:f}'.format(
- accuracy_score(pred_tests, test_y),
- precision_score(pred_tests, test_y),
- recall_score(pred_tests, test_y),
- f1_score(pred_tests, test_y))
- )
- 训练集正确率:0.925711,精确率:0.765743,召回率:0.534271,F1-Score:0.629400
- 测试集正确率:0.917910,精确率:0.591837,召回率:0.547170,F1-Score:0.568627
可以看出,经过特征选择后,测试集的预测 F1-Score 从 0.460526 提升到 0.568627,同时由于特征维度的降低,运行速度也加快!
网络流量分类或网络流量异常检测,采用基于聚类的机器学习算法,实现异常检测与分类,即划分为正常流量和异常流量。 本项目利用 pandas + Matplotlib + seaborn + sklearn 对网络流量数据进行统计分析,并构建聚类算法实现对流量的分类建模。
欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。
技术交流认准下方 CSDN 官方提供的学长 QQ 名片 :)
精彩专栏推荐订阅: