作者:yueji0j1anke
首发于公号:剑客古月的安全屋
字数:3323
阅读时间: 15min
声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。本文章内容纯属虚构,如遇巧合,纯属意外
目录
-
前言
-
数据分析
-
数据预处理
-
建模分析
-
重构
-
模型评估
-
总结
0x00 前言
本文基于AE模型,对信用卡欺诈相关数据集进行建模分析,从0-1识别欺诈案例
0x01 数据分析
数据集来源 https://www.kaggle.com/mlg-ulb/creditcardfraud
此数据集显示了两天内发生的交易,其中 284,807 笔交易中有 492 笔欺诈。数据集高度不平衡,正类(欺诈)占所有交易的 0.172%。
它仅包含作为 PCA 转换结果的数值输入变量。遗憾的是,由于机密性问题,我们无法提供有关数据的原始特征和更多背景信息。功能 V1、V2、...V28 是使用 PCA 获得的主成分,唯一未使用 PCA 转换的特征是 'Time' 和 'Amount'。特征 'Time' 包含数据集中每个事务与第一个事务之间经过的秒数。功能 'Amount' 是交易金额,此功能可用于依赖于成本的学习。特征 'Class' 是响应变量,在欺诈的情况下取值 1,否则取值 0。
老规矩,还是先看看数据
时间,amount,class,为没有转换的特征
看看是否有缺失
看看差异数量
差异量级较大
0x02 数据预处理
这里时序并没有用处,类似于序号了,可以进行删除避免干扰
同时 amount
金额差异大,需标准化处理
我们先保留正常样本进行训练得到正常模型
同时我们提取欺诈数据等会进行测试
0x03 建模分析
首先确定参数
-
输入特征数(共30维);
-
设置编码层维度为16;
-
训练轮数设为5;
-
每批样本大小为32。
接下来构建一个AE神经网络
由编码器 + 解码器组成;
1.输入层
定义输入层,input_dim 是输入数据的特征维度(比如 29,即 V1 ~ V28 和 Amount,共 29 个输入特征)告诉模型:每一行输入样本是一个长度为 input_dim 的向量
// 定义输入层,input_dim 是输入数据的特征维度(比如 29,即 V1 ~ V28 和 Amount,共 29 个输入特征)告诉模型:每一行输入样本是一个长度为 input_dim 的向量
input_layer = Input(shape=(input_dim, ))
2.Encoder
添加第一个隐藏层(编码器部分):
-
Dense(encoding_dim, ...)
:表示全连接层,节点数是encoding_dim
(这里是 16) -
activation="tanh"
:使用tanh
作为激活函数(非线性转换) -
activity_regularizer=regularizers.l1(10e-5)
:使用 L1 正则化防止过拟合,鼓励模型稀疏表示
encoder = Dense(encoding_dim, activation="tanh", activity_regularizer=regularizers.l1(10e-5))(input_layer)
这个层可以将输入压缩到一个较小的表示。
同时我们添加第二个隐藏层
encoder = Dense(int(encoding_dim / 2), activation="relu")(encoder)
继续缩小维度(变为 8):
-
激活函数换成了
ReLU
-
这继续进行信息压缩,提取更深层次的特征
3.Decoder
开始解压数据
第一层解压,尺寸从 8 → 8(对称结构)激活函数为 tanh
decoder = Dense(int(encoding_dim / 2), activation='tanh')(encoder)
最后一层将特征维度还原回 input_dim
,也就是原始输入维度(29):
-
激活函数为
ReLU
-
模型的输出与原始输入形状相同,用于计算重构误差
decoder = Dense(input_dim, activation='relu')(decoder)
最后构建一个完整的模型,并进行编译
autoencoder = Model(inputs=input_layer, outputs=decoder)
utoencoder.compile(optimizer='adam', loss='mean_squared_error', metrics=['mae'])
optimizer='adam'
:使用 Adam 优化器,效果稳定
loss='mean_squared_error'
:损失函数用 MSE(重构误差越小越好)
metrics=['mae']
:额外记录 MAE(平均绝对误差)作为参考指标
接下来开始训练,我们先定一个回调函数保存模型
checkpointer = ModelCheckpoint(filepath="model.h5", verbose=0, save_best_only=True)
开始训练,并记录训练中的loss和mae
history = autoencoder.fit(X_train, X_train,
epochs=num_epoch,
batch_size=batch_size,
shuffle=True, //数据集每次打乱
validation_data=(X_test, X_test),
verbose=1,
callbacks=[checkpointer]).history
plt.subplot(121) # 在1行2列的第1个子图
plt.plot(history['loss'], c='dodgerblue', lw=3) # 训练集损失,颜色蓝色,线宽3
plt.plot(history['val_loss'], c='coral', lw=3) # 验证集损失,颜色橙色,线宽3
plt.title('model loss') # 标题
plt.ylabel('mse') # y轴标签:均方误差
plt.xlabel('epoch') # x轴标签:训练轮次
plt.legend(['train', 'test'], loc='upper right') # 图例,右上角显示“train”和“test”
plt.subplot(122) # 在1行2列的第2个子图
plt.plot(history['mae'], c='dodgerblue', lw=3) # 训练集MAE,蓝色线
plt.plot(history['val_mae'], c='coral', lw=3) # 验证集MAE,橙色线
plt.title('model mae') # 标题
plt.ylabel('mae') # y轴标签
plt.xlabel('epoch') # x轴标签
plt.legend(['train', 'test'], loc='upper right') # 图例
可以看到第五个epoch出现了过拟合现象
0x04 重构评估
autoencoder = load_model('model.h5')
# 利用autoencoder重建测试集
pred_test = autoencoder.predict(X_test)
# 重建欺诈样本
pred_fraud = autoencoder.predict(X_fraud)
重构数据
mse_test = np.mean(np.power(X_test - pred_test, 2), axis=1)
mse_fraud = np.mean(np.power(X_fraud - pred_fraud, 2), axis=1)
mae_test = np.mean(np.abs(X_test - pred_test), axis=1)
mae_fraud = np.mean(np.abs(X_fraud - pred_fraud), axis=1)
构建一个包含“重构误差(MSE、MAE)”和“是否为欺诈”的完整数据集
mse_df = pd.DataFrame()
mse_df['Class'] = [0] * len(mse_test) + [1] * len(mse_fraud)
mse_df['MSE'] = np.hstack([mse_test, mse_fraud])
mse_df['MAE'] = np.hstack([mae_test, mae_fraud])
mse_df = mse_df.sample(frac=1).reset_index(drop=True)
打乱顺序
frac=1
:表示抽取全部样本进行随机打乱(即打乱整个数据集)。
reset_index(drop=True)
:重置索引并删除旧索引,避免索引混乱。
0x05 数据可视化
markers = ['o', '^'] # 图中用的点的形状,'o'表示圆形(正常),'^'表示三角形(欺诈)
colors = ['dodgerblue', 'coral'] # 蓝色代表正常,珊瑚色代表欺诈
labels = ['Non-fraud', 'Fraud'] # 标签:非欺诈 vs 欺诈
1.绘制MAE与MSE重构
plt.figure(figsize=(14, 5))
plt.subplot(121) # 1行2列的第1个子图(左图)
for flag in [1, 0]:
temp = mse_df[mse_df['Class'] == flag] # 筛选出当前类(0 = 正常,1 = 欺诈)
plt.scatter(
temp.index, # 横轴是样本的索引(打乱顺序后的 index)
temp['MAE'], # 纵轴是该样本的 MAE 重构误差
alpha=0.7, # 设置点的透明度
marker=markers[flag], # 点的形状(正常 o,欺诈 ^)
c=colors[flag], # 点的颜色(正常 蓝,欺诈 橘)
label=labels[flag] # 图例标签(Non-fraud / Fraud)
)
plt.subplot(122) # 子图2:MSE
for flag in [1, 0]:
temp = mse_df[mse_df['Class'] == flag]
plt.scatter(temp.index, temp['MSE'], alpha=0.7, marker=markers[flag], c=colors[flag], label=labels[flag])
plt.legend(loc=[1, 0], fontsize=12); plt.title('Reconstruction MSE')
plt.ylabel('Reconstruction MSE'); plt.xlabel('Index')
plt.show()
可以看到橘黄色三角形都是欺骗点,MAE和MSE都偏大
2.Precision-Recall 曲线
绘制 精确率-召回率曲线
在PR中,我们关注两个指标
指标 | 公式 | 含义(在欺诈检测中) |
---|---|---|
Precision 精确率 | TP / (TP + FP) |
模型预测为“欺诈”的交易中,实际有多少是真的 |
Recall 召回率 | TP / (TP + FN) |
所有真实欺诈交易中,模型成功发现了多少 |
-
TP(True Positive):真实是欺诈,模型也预测为欺诈
-
FP(False Positive):真实是正常,模型误判为欺诈
-
FN(False Negative):真实是欺诈,模型没发现,预测成了正常
plt.figure(figsize=(14, 6))
fori, metricinenumerate(['MAE', 'MSE']):
plt.subplot(1, 2, i+1)
precision, recall, _ = precision_recall_curve(mse_df['Class'], mse_df[metric])
pr_auc = auc(recall, precision)
plt.title('Precision-Recall curve based on %snAUC = %0.2f'% (metric, pr_auc))
plt.plot(recall[:-2], precision[:-2], c='coral', lw=4)
plt.xlabel('Recall'); plt.ylabel('Precision')
plt.show()
同时我们绘制点,需要去除 返回的最后几个点,因当:
-
样本极度不平衡(比如欺诈样本特别少),
-
或者误差分布接近时,PR 曲线最后会出现“跳跃”或“直线坠落”
可能会不稳定或极端情况出现
均在0.5以上,有用,但效果一般。。
3.ROC曲线
plt.figure(figsize=(14, 6))
for i, metric in enumerate(['MAE', 'MSE']):
plt.subplot(1, 2, i+1)
fpr, tpr, _ = roc_curve(mse_df['Class'], mse_df[metric])
roc_auc = auc(fpr, tpr)
plt.title('Receiver Operating Characteristic based on %snAUC = %0.2f' % (metric, roc_auc))
plt.plot(fpr, tpr, c='coral', lw=4)
plt.plot([0, 1], [0, 1], c='dodgerblue', ls='--')
plt.ylabel('TPR'); plt.xlabel('FPR')
plt.show()
这个效果蛮不错,整体分类性能
最后赋个散点图
markers = ['o', '^']
colors = ['dodgerblue', 'coral']
labels = ['Non-fraud', 'Fraud']
plt.figure(figsize=(10, 5))
forflagin [1, 0]:
temp = mse_df[mse_df['Class'] == flag]
plt.scatter(temp['MAE'],
temp['MSE'],
alpha=0.7,
marker=markers[flag],
c=colors[flag],
label=labels[flag])
plt.legend(loc=[1, 0])
plt.ylabel('Reconstruction RMSE'); plt.xlabel('Reconstruction MAE')
plt.show()
0x06 总结
本文从数据集分析处理,发现数据类别样本数量差异大,最终选择AE模型进行建模分析,将数据时间与是否欺诈特征舍弃进行无监督学习,最后构建出新的数据集(类别0/1 MSE MAE)进行模型性能评估,包括PR曲线、ROC曲线去进行评估,最后的拟合效果可以说是非常好了。
原文始发于微信公众号(剑客古月的安全屋):ai攻防应用-基于AE神经网络模型 识别检测异常攻击欺诈
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论