你还在为数据枯燥而发愁?不如让我们用机器学习来和DDoS攻击“打个招呼”!
欢迎来到一场别开生面的数据科学冒险!你是否曾经面对一堆毫无生气的数据表格,感到头疼不已?是否在盯着屏幕苦苦寻找攻击模式时,觉得自己仿佛变成了一个被困在数据迷宫里的“网络侦探”?别担心!今天,我们要带你进入一个既充满技术含量又不乏趣味的世界——DDoS攻击数据分析与机器学习模型的终极指南。在这片神秘的网络战场上,我们不仅要识破每一个DDoS攻击的阴谋,还要用机器学习模型来“以智取胜”,确保你的数据科学之旅既有干货又有乐趣!
Step 1:数据合并——让散落的“数据英雄”集结
在数据科学的世界里,每一份数据都像是隐士高手,分散在各个角落。而我们的任务就是要把这些“数据英雄”召集到一起,形成一支强大的分析团队。在这个案例中,我们面对的是来自加拿大新不伦瑞克大学的网络情报与网络安全中心(CIC)的CICDDoS2019数据集——这个数据集记录了各种最新的DDoS攻击,就像一本充满悬念的侦探小说,等待我们去解读。
我们的第一个挑战就是将这些数据文件整合起来。想象一下,你要把来自不同来源的英雄集结成一支无敌的队伍,过程中还得筛选掉那些“经验不足”的队员(行数据)。我们通过随机选择跳过部分行数据,来确保数据的多样性和代表性。
# 初始化一个空的DataFrame来合并所有数据
all_data = pd.DataFrame()
# 循环读取每个文件,并将它们合并到all_data DataFrame
for file in files:
# 随机生成需要跳过的行号
skip_rows = np.random.choice(range(1, total_rows), replace=False,
size=max(0, total_rows - np.random.randint(3000, 15001)))
temp_df = pd.read_csv(file_path, skiprows=skip_rows)
temp_df['Attack Type'] = file.replace('.csv', '')
all_data = pd.concat([all_data, temp_df], ignore_index=True)
这段代码就像是一个魔法阵,悄无声息地将所有数据整合在一起,准备迎接后续的“战斗”。而接下来的步骤,就是让这些数据焕然一新,摆脱一切“噪音”。
Step 2:数据清理——为战斗准备一支“全副武装”的队伍
数据清理就像是一场盛大的宴会筹备,你必须确保每个细节都无懈可击。我们要做的第一件事,就是清理这些数据的外观,去除那些不必要的空白、填补缺失的值,确保每一个数据点都在最佳状态。
# 清理所有列名,去除前后的空格
data.columns = data.columns.str.strip()
data = data.replace([np.inf, -np.inf], np.nan)
data.fillna(data.median(numeric_only=True), inplace=True)
这些简单的操作就像是为数据“整装待发”,去除那些影响分析的“负担”,确保每个数据点都能够准确反映它的真实含义。接下来,我们要开始揭示数据中的“暗流涌动”。
Step 3:数据探索——发现隐藏在数据中的秘密
数据探索的阶段就像是侦探故事的高潮部分,你终于要揭开那些隐藏的真相了。我们会通过各种图表和统计分析,发现数据中那些不为人知的规律。
流量分布——谁在午夜时分发动攻击?
首先,我们会看看不同时间段的流量分布。你会发现,DDoS攻击者似乎喜欢在某些特定的时间点发动攻击,就像夜行侠一样,喜欢在黑暗中行动。
traffic_distribution = data['Hour'].value_counts().sort_index()
sns.countplot(x='Hour', data=data)
plt.title('流量分布 - 按小时')
plt.xlabel('小时')
plt.ylabel('流量计数')
plt.show()
攻击类型分析——DDoS攻击的幕后黑手到底是谁?
接下来,我们用饼图来分析不同攻击类型的分布情况。这个图表就像是一份DDoS攻击的“嫌疑人名单”,让我们一眼看清哪个攻击类型最猖獗。
data['Attack Type'].value_counts().plot(kind='pie', autopct='%1.1f%%')
plt.title('攻击类型分布')
plt.show()
这些分析不仅让我们对数据有了初步的了解,还为后续的模型训练提供了宝贵的线索。
Step 4:特征工程与模型训练——打造网络安全的“秘密武器”
现在,我们已经准备好进入数据科学的核心部分:特征工程与模型训练。我们会使用逻辑回归、随机森林和梯度提升决策树这三位“战士”来训练模型,最终找出最适合对抗DDoS攻击的“秘密武器”。
逻辑回归:简单直接的线性思路
逻辑回归是我们的第一个模型,就像是网络安全中的“直拳”,虽然简单直接,但非常有效。它能快速识别数据中的线性关系,让我们迅速了解数据的全貌。
lr_cv_model = LogisticRegressionCV(cv=5, max_iter=1000, class_weight='balanced',
solver='liblinear', scoring='accuracy', random_state=42)
lr_cv_model.fit(X_train_processed, y_train)
随机森林:来自自然界的强大力量
接下来登场的是随机森林,这是一种集成学习方法,结合了多棵决策树的智慧。它像是一个团队作战,通过集体决策来提高模型的稳定性和预测准确性。
pipeline = Pipeline([
('scaler', StandardScaler(with_mean=False)),
('feature_selection', SelectFromModel(RandomForestClassifier(n_estimators=100, random_state=42,
verbose=1))),
('classification', RandomForestClassifier(random_state=42))
])
梯度提升决策树:逐步改进的策略大师
最后,出场的是梯度提升决策树(GBDT),它以逐步改进的方式来训练模型,就像是一位深思熟虑的棋手,每一步都在朝着最终的胜利迈进。
gbdt = GradientBoostingClassifier(random_state=42)
grid_search.fit(X_train, y_train)
Step 5:模型评估与优化——确保战斗的胜利
经过一番训练之后,我们会对模型的表现进行评估,看看它们在对抗DDoS攻击时表现如何。通过准确率、召回率、F1分数等指标,我们能清楚地了解哪个模型更适合这场“战斗”。
完整代码如下:
import matplotlib.pyplot as plt
import matplotlib
# 指定字体为SimHei支持中文显示
matplotlib.rcParams['font.family'] = 'SimHei'
# 解决负号'-'显示为方块的问题
matplotlib.rcParams['axes.unicode_minus'] = False
import pandas as pd
# 加载数据
file_path = 'merged_dataset_varied_rows.csv' # 更改为您的文件路径
data = pd.read_csv(file_path)
# 修正列名,去除列名周围的空格
data.columns = data.columns.str.strip()
# 时间戳处理
data['Timestamp'] = pd.to_datetime(data['Timestamp'])
data['Hour'] = data['Timestamp'].dt.hour
# 基本统计分析
basic_stats = data.describe()
# 流量分布
traffic_distribution = data['Hour'].value_counts().sort_index()
# 攻击类型分析
attack_types = data['Attack Type'].value_counts()
# 数据包特征分析
packet_features_stats = data[['Total Fwd Packets', 'Total Backward Packets', 'Fwd Packet Length Max', 'Bwd Packet Length Max']].describe()
# 流量特征关联分析
correlation_matrix = data[['Flow Duration', 'Total Fwd Packets', 'Total Backward Packets', 'Fwd Packet Length Mean', 'Bwd Packet Length Mean']].corr()
# 打印分析结果
print("基本统计分析结果:")
print(basic_stats)
print("\n流量分布:")
print(traffic_distribution)
print("\n攻击类型分析:")
print(attack_types)
print("\n数据包特征分析:")
print(packet_features_stats)
print("\n流量特征关联分析:")
print(correlation_matrix)
import matplotlib.pyplot as plt
import seaborn as sns
# 流量分布柱状图
plt.figure(figsize=(10, 6))
sns.countplot(x='Hour', data=data)
plt.title('流量分布 - 按小时')
plt.xlabel('小时')
plt.ylabel('流量计数')
plt.show()
# 攻击类型分布饼图
plt.figure(figsize=(10, 8))
data['Attack Type'].value_counts().plot(kind='pie', autopct='%1.1f%%')
plt.title('攻击类型分布')
plt.ylabel('')
plt.show()
# 数据包特征的箱线图
plt.figure(figsize=(10, 6))
sns.boxplot(data=data[['Total Fwd Packets', 'Total Backward Packets']])
plt.title('数据包数量分布')
plt.show()
# 数据包长度的直方图
plt.figure(figsize=(10, 6))
data[['Fwd Packet Length Max', 'Bwd Packet Length Max']].hist(bins=30, alpha=0.7)
plt.title('数据包长度分布')
plt.show()
# 特征之间的相关性热图
plt.figure(figsize=(10, 8))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', linewidths=.5)
plt.title('特征之间的相关性热图')
plt.show()
#########################################################################################
#########################################################################################
"""
这个数据集由加拿大新不伦瑞克大学的网络情报与网络安全中心(CIC)提供,专注于DDoS攻击,这使它非常适合于网络安全研究和机器学习模型的训练。
CICDDoS2019数据集的特点如下:
最新的DDoS攻击模式:包含了最新的DDoS攻击类型,可以帮助模型学习识别当前和潜在的威胁模式。
详细的网络流量分析:使用CICFLOWMeter-V3工具进行分析,该工具提供了基于时间戳的令牌流、目标IPS源、端口协议等详细信息,
这些都是训练检测模型时的有价值特征。
接近真实世界的数据:数据集模拟了真实世界的网络环境,有助于开发能够在实际环境中有效工作的模型。
"""
#######################################################################################
#######################################################################################
##第一步,将文件夹中的所有文件整合到一起
#
# import pandas as pd
# import os
# import numpy as np
#
# # 定义数据文件的目录路径
# data_directory = './DATASET/' # 更新为您的数据集文件夹路径
#
# # 数据集文件列表
# files = [
# 'DrDoS_DNS.csv',
# 'DrDoS_LDAP.csv',
# 'DrDoS_MSSQL.csv',
# 'DrDoS_NetBIOS.csv',
# 'DrDoS_NTP.csv',
# 'DrDoS_SNMP.csv',
# 'DrDoS_SSDP.csv',
# 'DrDoS_UDP.csv',
# 'Syn.csv',
# 'TFTP.csv',
# 'UDPLag.csv'
# ]
#
# # 初始化一个空的DataFrame来合并所有数据
# all_data = pd.DataFrame()
#
# # 循环读取每个文件,并将它们合并到all_data DataFrame
# for file in files:
# file_path = os.path.join(data_directory, file)
#
# # 确定每个文件的行数
# total_rows = sum(1 for row in open(file_path, 'r', encoding='utf-8'))
#
# # 随机生成需要跳过的行号
# skip_rows = np.random.choice(range(1, total_rows), replace=False,
# size=max(0, total_rows - np.random.randint(3000, 15001)))
#
# # 读取文件,跳过随机选定的行
# temp_df = pd.read_csv(file_path, skiprows=skip_rows)
#
# # 添加一个新列来标示攻击类型,从文件名提取
# temp_df['Attack Type'] = file.replace('.csv', '')
#
# # 合并到大的DataFrame中
# all_data = pd.concat([all_data, temp_df], ignore_index=True)
#
# # 检查合并后的数据集大小和前几行数据
# print(all_data.shape)
# print(all_data.head())
#
# # 可选:保存合并后的数据集到一个新的CSV文件
# all_data.to_csv('merged_dataset_varied_rows.csv', index=False) # 更新保存路径
#######################################################################################
#######################################################################################
##第二步,数据预处理步骤的代码。
# 这些步骤包括数据清洗、处理缺失值、编码分类变量、特征缩放和数据集分割:
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from scipy import sparse
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib
# 指定字体为SimHei支持中文显示
matplotlib.rcParams['font.family'] = 'SimHei'
# 解决负号'-'显示为方块的问题
matplotlib.rcParams['axes.unicode_minus'] = False
# 加载数据集
data = pd.read_csv('merged_dataset_varied_rows.csv')
# 清理所有列名,去除前后的空格
data.columns = data.columns.str.strip()
# 替换无穷大值为NaN
data = data.replace([np.inf, -np.inf], np.nan)
# 使用中位数填充所有NaN值
data.fillna(data.median(numeric_only=True), inplace=True)
# 数据清洗
data.drop(columns=['Unnamed: 0'], inplace=True)
# 解决混合类型问题:将所有object类型的列转换为字符串,确保一致性
for col in data.select_dtypes(include=['object']).columns:
data[col] = data[col].astype(str)
# 缺失值处理:只对数值列使用中位数填充
numeric_cols = data.select_dtypes(include=['int64', 'float64']).columns
data[numeric_cols] = data[numeric_cols].fillna(data[numeric_cols].median())
# 时间特征处理
data['Timestamp'] = pd.to_datetime(data['Timestamp'])
data['Hour'] = data['Timestamp'].dt.hour
data['DayOfWeek'] = data['Timestamp'].dt.dayofweek
# 识别数值型特征和分类特征
numeric_features = data.select_dtypes(include=['int64', 'float64']).columns
categorical_features = data.select_dtypes(include=['object']).columns
categorical_features = categorical_features.drop(['Flow ID', 'Source IP', 'Destination IP'])
# 将分类特征列的数据类型统一为字符串
categorical_features = data.select_dtypes(include=['object']).columns
data[categorical_features] = data[categorical_features].astype(str)
# 特征与目标变量之间的关系
# 数值特征与目标变量
# 由于可能存在大量的数值特征,我们可能仅选择几个进行展示
selected_numeric_features = numeric_features[:4] # 示例:选取前四个数值特征
for feature in selected_numeric_features:
plt.figure(figsize=(10, 6))
sns.boxplot(x='Label', y=feature, data=data)
plt.title(f'{feature} 在不同 Label 下的分布情况')
plt.xticks(rotation=45)
plt.show()
## 这个比较耗时
# 类别特征与目标变量
# 对于已经独热编码的类别特征,此分析应在编码之前完成
# selected_categorical_features = categorical_features[:4] # 示例:选取前四个类别特征
# for feature in selected_categorical_features:
# feature_count = pd.crosstab(index=data[feature], columns=data['Label'])
# feature_count.plot(kind='bar', stacked=True, figsize=(10, 6))
# plt.title(f'{feature} 在不同 Label 下的分布情况')
# plt.xlabel(feature)
# plt.ylabel('频数')
# plt.xticks(rotation=45)
# plt.show()
## 4. 特征之间的相关性
plt.figure(figsize=(10, 8))
selected_numeric_features_tmp = numeric_features[:15] # 示例:选取前四个数值特征
corr = data[selected_numeric_features_tmp].corr()
sns.heatmap(corr, annot=True, cmap='coolwarm', fmt=".2f")
plt.title('数值特征间的相关性热力图')
plt.show()
# 构建预处理管道
numeric_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())])
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
('onehot', OneHotEncoder(handle_unknown='ignore'))])
preprocessor = ColumnTransformer(
transformers=[
('num', numeric_transformer, numeric_features),
('cat', categorical_transformer, categorical_features)])
# 应用预处理
data_preprocessed = preprocessor.fit_transform(data)
# 分割数据集
y = data['Label'] # 假设Label列已经被转换为了合适的格式
X = data_preprocessed
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# # 6. 经过PCA或其他降维技术处理后的可视化
from sklearn.decomposition import TruncatedSVD
# 初始化TruncatedSVD
svd = TruncatedSVD(n_components=2)
# 在预处理后的数据X上应用TruncatedSVD
svd_result = svd.fit_transform(X)
# 可视化降维后的数据
plt.figure(figsize=(10, 6))
sns.scatterplot(x=svd_result[:, 0], y=svd_result[:, 1], hue=data['Label'].tolist(), palette='rainbow')
plt.title('TruncatedSVD 降维后的数据分布')
plt.xlabel('SVD1')
plt.ylabel('SVD2')
plt.show()
#############################################################################################
#############################################################################################
# ##第三步 模型训练及性能分析
## 3.1 逻辑回归模型训练及性能分析
from sklearn.model_selection import train_test_split, StratifiedKFold
from sklearn.metrics import classification_report, accuracy_score
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression, LogisticRegressionCV
# 数据集划分:70%训练集,30%测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 特征选择:以逻辑回归的系数作为特征重要性的依据进行选择
# 注意:这里仅作为示例,实际应用中可能需要根据具体情况调整
preprocess_pipeline = make_pipeline(StandardScaler(with_mean=False), SelectFromModel(LogisticRegression(class_weight='balanced', solver='liblinear', max_iter=1000)))
X_train_processed = preprocess_pipeline.fit_transform(X_train, y_train)
X_test_processed = preprocess_pipeline.transform(X_test)
# 使用LogisticRegressionCV进行交叉验证,自动选择正则化强度
lr_cv_model = LogisticRegressionCV(cv=5, max_iter=1000, class_weight='balanced',
solver='liblinear', scoring='accuracy', random_state=42,verbose=1)
# 训练模型
lr_cv_model.fit(X_train_processed, y_train)
# 预测测试集
y_pred_lr = lr_cv_model.predict(X_test_processed)
# 性能分析
print("经过特征选择后的逻辑回归模型性能:")
print(classification_report(y_test, y_pred_lr))
print("准确度:", accuracy_score(y_test, y_pred_lr))
#####################################################################################################
#####################################################################################################
## 采用随机森林
from sklearn.model_selection import train_test_split, StratifiedKFold, GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, accuracy_score
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.feature_selection import SelectFromModel
# 数据预处理和特征选择
pipeline = Pipeline([
('scaler', StandardScaler(with_mean=False)),
('feature_selection', SelectFromModel(RandomForestClassifier(n_estimators=100, random_state=42,
verbose=1))),
('classification', RandomForestClassifier(random_state=42))
])
# 分割数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42,)
# 参数网格
param_grid = {
'classification__n_estimators': [100, 200],
'classification__max_depth': [None, 10, 20],
'classification__min_samples_split': [2, 5],
'classification__min_samples_leaf': [1, 2],
'classification__class_weight': [None, 'balanced']
}
# 使用网格搜索进行参数调优
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
grid_search = GridSearchCV(pipeline, param_grid, cv=cv, scoring='accuracy', n_jobs=-1)
grid_search.fit(X_train, y_train)
print(f"最佳参数: {grid_search.best_params_}")
print(f"最佳交叉验证准确度: {grid_search.best_score_}")
# 使用最佳参数的模型进行预测
y_pred_rf = grid_search.predict(X_test)
# 性能分析
print("随机森林模型性能:")
print(classification_report(y_test, y_pred_rf))
print("准确度:", accuracy_score(y_test, y_pred_rf))
#
# # ############################################################################################################
# # ############################################################################################################
# ## 方法3 采用梯度提升决策树(Gradient Boosting Decision Trees, GBDT)
#
# from sklearn.model_selection import GridSearchCV
# from sklearn.ensemble import GradientBoostingClassifier
# from sklearn.ensemble import GradientBoostingClassifier
# from sklearn.metrics import classification_report, accuracy_score
# from sklearn.model_selection import train_test_split, GridSearchCV
# # 定义要搜索的参数网格
# param_grid = {
# 'n_estimators': [100, 200, 300], # 弱学习器的数量,也就是树的数量
# 'learning_rate': [0.1, 0.05, 0.01], # 学习率,控制每棵树对最终结果的贡献
# 'max_depth': [3, 4, 5], # 每棵树的最大深度
# 'min_samples_split': [2, 4], # 分裂内部节点所需的最小样本数
# 'min_samples_leaf': [1, 2], # 在叶节点处需要的最小样本数
# 'max_features': ['sqrt', 'log2', None] # 寻找最佳分裂时要考虑的特征数量
# }
#
# # 初始化GBDT模型
# gbdt = GradientBoostingClassifier(random_state=42)
#
# # 创建GridSearchCV对象进行参数搜索
# grid_search = GridSearchCV(estimator=gbdt, param_grid=param_grid, cv=5, scoring='accuracy', n_jobs=-1, verbose=2)
#
# # 执行网格搜索
# grid_search.fit(X_train, y_train)
#
# # 输出最优参数和对应的评分
# print(f"最佳参数: {grid_search.best_params_}")
# print(f"最佳准确度: {grid_search.best_score_}")
#
# # 使用最优参数的模型进行预测
# y_pred_gbdt_optimized = grid_search.predict(X_test)
#
# # 性能评估
# print("使用最优参数的GBDT模型性能:")
# print(classification_report(y_test, y_pred_gbdt_optimized))
# print("准确度:", accuracy_score(y_test, y_pred_gbdt_optimized))
结语:数据科学的终极武器
从数据准备到模型训练,我们一步步揭开了DDoS攻击的神秘面纱,并打造出了一套强大的网络安全解决方案。希望这篇博客不仅为你提供了技术上的帮助,也让你在数据分析的过程中收获了一些乐趣和成就感。
在这个快速变化的技术世界里,数据科学不再是冰冷的数字和复杂的代码,而是一场充满智慧与策略的冒险。无论是面对DDoS攻击还是其他挑战,只要我们保持好奇心和探索精神,就一定能找到最优的解决方案。祝你在未来的编程旅程中,继续发现数据的无限可能,成为真正的技术大师!