来源:https://mp.weixin.qq.com/s?__biz=MzA4OTAwMjY2Nw==&mid=2650190833&idx=1&sn=3cb27f10dfb86b0f397891f472796cdd&chksm=88239435bf541d23c1149d59eab8d766a22a1a46d85f2b8c89a1ecfb0ac1e58d963ac3d749c7&scene=21#wechat_redirect

基于深度学习Autoencoder的信用卡欺诈异常检测 - 图1
大家好,我是小伍哥,今天接着搞异常检测。异常检测断断续续写了好几篇的,合集请看:异常检测算法汇总
深度学习用于异常检测,效果还是相当牛逼的。信用卡欺诈数据集,在孤立森林上能做到26%的top1000准确率,但是在Autoencoder算法上,最高做到了33.6%,但是这个数据很不稳定,有时候只有25%左右,但是至少这个模型潜力巨大,需要更多的试验,找到更稳定的网络结构。
基于深度学习Autoencoder的信用卡欺诈异常检测 - 图2
自编码器(AutoEncoder, AE)是一类在半监督学习和非监督学习中使用的人工神经网络,其功能是通过将输入信息作为学习目标,对输入信息进行表征学习(representation learning),自编码器包含编码器(encoder)解码器(decoder)两部分 。
AutoEncoder是深度学习的一个重要内容,并且非常有意思,神经网络通过大量数据集,进行end-to-end的训练,不断提高其准确率,而AutoEncoder通过设计encode和decode过程使输入和输出越来越接近,是一种无监督学习过程,可以被应用于降维(dimensionality reduction)和异常值检测(anomaly detection),包含卷积层构筑的自编码器可被应用于计算机视觉问题,包括图像降噪(image denoising) 、神经风格迁移(neural style transfer)等 ,本文主要讲解如何利用AutoEncoder进行异常检测试验。
用AutoEncoder进行降噪,可以看到通过卷积自编码器,我们的降噪效果还是非常好的,最终生成的图片看起来非常顺滑,噪声也几乎看不到了。
基于深度学习Autoencoder的信用卡欺诈异常检测 - 图3
用AutoEncoder进行降维。
基于深度学习Autoencoder的信用卡欺诈异常检测 - 图4

一、Autoencoder结构简介

Autoencoder本质上它使用了一个神经网络来产生一个高维输入的低维表,Autoencoder与主成分分析PCA类似,但是Autoencoder在使用非线性激活函数时克服了PCA线性的限制。
Autoencoder包含两个主要的部分,encoder(编码器)和 decoder(解码器)。Encoder的作用是用来发现给定数据的压缩表示,decoder是用来重建原始输入。在训练时,decoder 强迫 autoencoder 选择最有信息量的特征,最终保存在压缩表示中。最终压缩后的表示就在中间的coder层当中。
以下图为例,原始数据的维度是10,encoder和decoder分别有两层,中间的coder共有3个节点,也就是说原始数据被降到了只有3维。Decoder根据降维后的数据再重建原始数据,重新得到10维的输出。从Input到Ouptut的这个过程中,autoencoder实际上也起到了降噪的作用。
基于深度学习Autoencoder的信用卡欺诈异常检测 - 图5

二、Autoencoder异常检测流程

异常检测(anomaly detection)通常分为有监督和无监督两种情形。在无监督的情况下,我们没有异常样本用来学习,而算法的基本上假设是异常点服从不同的分布。根据正常数据训练出来的Autoencoder,能够将正常样本重建还原,但是却无法将异于正常分布的数据点较好地还原,导致还原误差较大。
如果样本的特征都是数值变量,我们可以用MSE或者MAE作为还原误差。例如上图,如果输入样本为
基于深度学习Autoencoder的信用卡欺诈异常检测 - 图6
经过Autoencoder重建的结果为
基于深度学习Autoencoder的信用卡欺诈异常检测 - 图7
还原误差MSE为
基于深度学习Autoencoder的信用卡欺诈异常检测 - 图8
还原误差MAE为
基于深度学习Autoencoder的信用卡欺诈异常检测 - 图9

三、模型算法过程

数据还是使用信用卡的数据,数据来自于kaggle上的一个信用卡欺诈检测比赛,数据质量高,正负样本比例非常悬殊,很典型的异常检测数据集,在这个数据集上来测试一下各种异常检测手段的效果。当然,可能换个数据集结果就会有很大不同,结果仅供参考。

全文代码汇总:

  1. # -*- coding: utf-8 -*-
  2. # 加载所需要的包
  3. import warnings
  4. warnings.filterwarnings("ignore")
  5. import os
  6. import pandas as pd
  7. import numpy as np
  8. import matplotlib.pyplot as plt
  9. #plt.style.use('seaborn')
  10. import tensorflow as tf
  11. import seaborn as sns
  12. from sklearn.model_selection import train_test_split
  13. from keras.models import Model, load_model
  14. from keras.layers import Input, Dense,LeakyReLU,BatchNormalization
  15. from keras.callbacks import ModelCheckpoint
  16. from keras import regularizers
  17. from sklearn.preprocessing import StandardScaler
  18. from sklearn.metrics import roc_curve, auc, precision_recall_curve
  19. # 解决报错“ImportError: cannot import name 'get_config' from 'tensorflow.python.eager.context'”
  20. # 升级 tensorflow
  21. # 工作空间设置
  22. os.chdir('/Users/yingtao.xiang/Downloads/archive/')
  23. os.getcwd()
  24. # 读取数据
  25. d = pd.read_csv('creditcard.csv')
  26. # 查看样本比例
  27. num_nonfraud = np.sum(d['Class'] == 0)
  28. num_fraud = np.sum(d['Class'] == 1)
  29. plt.bar(['Fraud', 'non-fraud'], [num_fraud, num_nonfraud], color='dodgerblue')
  30. plt.show()
  31. # 删除时间列,对Amount进行标准化
  32. data = d.drop(['Time'], axis=1)
  33. data['Amount'] = StandardScaler().fit_transform(data[['Amount']])
  34. X = data.drop(['Class'],axis=1)
  35. Y = data.Class
  36. # 设置Autoencoder的参数
  37. input_dim = X.shape[1]
  38. encoding_dim = 128
  39. num_epoch = 30
  40. batch_size = 256
  41. input_layer = Input(shape=(input_dim, ))
  42. encoder = Dense(encoding_dim,
  43. activation="tanh",
  44. activity_regularizer=regularizers.l1(10e-5)
  45. )(input_layer)
  46. encoder =BatchNormalization()(encoder)
  47. encoder=LeakyReLU(alpha=0.2)(encoder)
  48. encoder = Dense(int(encoding_dim/2),
  49. activation="relu"
  50. )(encoder)
  51. encoder =BatchNormalization()(encoder)
  52. encoder=LeakyReLU(alpha=0.1)(encoder)
  53. encoder = Dense(int(encoding_dim/4),
  54. activation="relu"
  55. )(encoder)
  56. encoder =BatchNormalization()(encoder)
  57. ### decoder
  58. decoder = LeakyReLU(alpha=0.1)(encoder)
  59. decoder = Dense(int(encoding_dim/4),
  60. activation='tanh'
  61. )(decoder)
  62. decoder = BatchNormalization()(decoder)
  63. decoder = LeakyReLU(alpha=0.1)(decoder)
  64. decoder = Dense(int(encoding_dim/2),
  65. activation='tanh'
  66. )(decoder)
  67. decoder = BatchNormalization()(decoder)
  68. decoder = LeakyReLU(alpha=0.1)(decoder)
  69. decoder = Dense(input_dim,
  70. #activation='relu'
  71. )(decoder)
  72. autoencoder = Model(inputs = input_layer,
  73. outputs = decoder
  74. )
  75. autoencoder.compile(optimizer='adam',
  76. loss='mean_squared_error',
  77. metrics=['mae','mse']
  78. )
  79. # 模型保存为 XiaoWuGe_model.h5,并开始训练模型
  80. checkpointer = ModelCheckpoint(filepath="XiaoWuGe_model.h5",
  81. verbose=0,
  82. save_best_only=True
  83. )
  84. history = autoencoder.fit(X,
  85. X,
  86. epochs=num_epoch,
  87. batch_size=batch_size,
  88. shuffle=True,
  89. #validation_data=(X_test, X_test),
  90. verbose=1,
  91. callbacks=[checkpointer]
  92. ).history
  93. # Epoch 1/30
  94. # 284807/284807 [==============================] - 39s 136us/step - loss: 0.6593 - mae: 0.3893 - mse: 0.4098
  95. # Epoch 2/30
  96. # Epoch 29/30
  97. # 284807/284807 [==============================] - 41s 144us/step - loss: 0.1048 - mae: 0.1188 - mse: 0.0558
  98. # Epoch 30/30
  99. # 284807/284807 [==============================] - 39s 135us/step - loss: 0.0891 - mae: 0.1134 - mse: 0.0495
  100. # 模型结果可视化
  101. # 画出损失函数曲线
  102. plt.figure(figsize=(14, 5))
  103. plt.subplot(121)
  104. plt.plot(history['loss'], c='dodgerblue', lw=3)
  105. plt.title('model loss')
  106. plt.ylabel('mse')
  107. plt.xlabel('epoch')
  108. plt.legend(['train'], loc='upper right')
  109. # 画出损失函数曲线
  110. plt.figure(figsize=(14, 5))
  111. plt.subplot(121)
  112. plt.plot(history['mae'], c='dodgerblue', lw=3)
  113. plt.title('model mae')
  114. plt.ylabel('mae')
  115. plt.xlabel('epoch')
  116. plt.legend(['train'], loc='upper right')
  117. # 画出损失函数曲线
  118. plt.figure(figsize=(14, 5))
  119. plt.subplot(121)
  120. plt.plot(history['mse'], c='dodgerblue', lw=3)
  121. plt.title('model mse')
  122. plt.ylabel('mse')
  123. plt.xlabel('epoch')
  124. plt.legend(['train'], loc='upper right')
  125. # 模型结果预测
  126. #利用训练好的autoencoder重建测试集
  127. pred_X = autoencoder.predict(X)
  128. # 计算还原误差MSE和MAE
  129. mse_X = np.mean(np.power(X-pred_X,2), axis=1)
  130. mae_X = np.mean(np.abs(X-pred_X), axis=1)
  131. data['mse_X'] = mse_X
  132. data['mae_X'] = mae_X
  133. # TopN准确率评估
  134. n = 1000
  135. df = data.sort_values(by='mae_X',ascending=False)
  136. df = df.head(n)
  137. rate = df[df['Class']==1].shape[0]/n
  138. print('Top{}的准确率为:{}'.format(n,rate))
  139. # Top1000的准确率为:0.336
  140. # 我实际跑出来:Top1000的准确率为:0.145
  141. # 可以看到,我们的准确率为0.336,比之前的孤立森林又有了很大的提高,但是我经过了比较多的试验,这是比较理想的结果。
  142. # 下面我可以可以看看,正样本和负样本的一个分布差异。
  143. # 提取负样本,并且按照7:3切成训练集和测试集
  144. mask = (data['Class'] == 0)
  145. X_train, X_test = train_test_split(X, test_size=0.3,
  146. random_state=520)
  147. # 提取所有正样本,作为测试集的一部分
  148. X_fraud = X[~mask]
  149. # 利用训练好的autoencoder重建测试集
  150. pred_test = autoencoder.predict(X_test)
  151. pred_fraud = autoencoder.predict(X_fraud)
  152. # 计算还原误差MSE和MAE
  153. mse_test = np.mean(np.power(X_test - pred_test, 2), axis=1)
  154. mse_fraud = np.mean(np.power(X_fraud - pred_fraud, 2), axis=1)
  155. mae_test = np.mean(np.abs(X_test - pred_test), axis=1)
  156. mae_fraud = np.mean(np.abs(X_fraud - pred_fraud), axis=1)
  157. mse_df = pd.DataFrame()
  158. mse_df['Class'] = [0] * len(mse_test) + [1] * len(mse_fraud)
  159. mse_df['MSE'] = np.hstack([mse_test, mse_fraud])
  160. mse_df['MAE'] = np.hstack([mae_test, mae_fraud])
  161. mse_df = mse_df.sample(frac=1).reset_index(drop=True)
  162. # 分别画出测试集中正样本和负样本的还原误差MAE和MSE
  163. markers = ['o', '^']
  164. markers = ['o', '^']
  165. colors = ['dodgerblue', 'red']
  166. labels = ['Non-fraud', 'Fraud']
  167. plt.figure(figsize=(14, 5))
  168. plt.subplot(121)
  169. for flag in [1, 0]:
  170. temp = mse_df[mse_df['Class'] == flag]
  171. plt.scatter(temp.index,
  172. temp['MAE'],
  173. alpha=0.7,
  174. marker=markers[flag],
  175. c=colors[flag],
  176. label=labels[flag])
  177. plt.title('Reconstruction MAE')
  178. plt.ylabel('Reconstruction MAE')
  179. plt.xlabel('Index')
  180. plt.subplot(122)
  181. for flag in [1, 0]:
  182. temp = mse_df[mse_df['Class'] == flag]
  183. plt.scatter(temp.index,
  184. temp['MSE'],
  185. alpha=0.7,
  186. marker=markers[flag],
  187. c=colors[flag],
  188. label=labels[flag])
  189. plt.legend(loc=[1, 0], fontsize=12)
  190. plt.title('Reconstruction MSE')
  191. plt.ylabel('Reconstruction MSE')
  192. plt.xlabel('Index')
  193. plt.show()

1、数据集介绍

信用卡欺诈是指故意使用伪造、作废的信用卡,冒用他人的信用卡骗取财物,或用本人信用卡进行恶意透支的行为,信用卡欺诈形式分为3种:失卡冒用、假冒申请、伪造信用卡。欺诈案件中,有60%以上是伪造信用卡诈骗,其特点是团伙性质,从盗取卡资料、制造假卡、贩卖假卡,到用假卡作案,牟取暴利。而信用卡欺诈检测是银行减少损失的重要手段。
该数据集包含欧洲持卡人于 2013 年 9 月通过信用卡进行的交易信息。此数据集显示的是两天内发生的交易,在 284807 笔交易中,存在 492 起欺诈,数据集高度不平衡,正类(欺诈)仅占所有交易的 0.172%。原数据集已做脱敏处理和PCA处理,匿名变量V1, V2, …V28 是 PCA 获得的主成分,唯一未经过 PCA 处理的变量是 Time 和 Amount。Time 是每笔交易与数据集中第一笔交易之间的间隔,单位为秒;Amount 是交易金额。Class 是分类变量,在发生欺诈时为1,否则为0。项目要求根据现有数据集建立分类模型,对信用卡欺诈行为进行检测。
注:PCA - “Principal Component Analysis” - 主成分分析,用于提取数据集的”主成分”特征,即对数据集进行降维处理。

2、数据来源

数据集 Credit Card Fraud Detection 由比利时布鲁塞尔自由大学(ULB) - Worldline and the Machine Learning Group 提供。可从Kaggle上下载:https://www.kaggle.com/mlg-ulb/creditcardfraud
不想自己下载数据的,后台回复【信用卡欺诈】领取。

3、模型搭建

需要的包比较多,我们先加载下

  1. # 加载所需要的包
  2. import warnings
  3. warnings.filterwarnings("ignore")
  4. import os
  5. import pandas as pd
  6. import numpy as np
  7. import matplotlib.pyplot as plt
  8. #plt.style.use('seaborn')
  9. import tensorflow as tf
  10. import seaborn as sns
  11. from sklearn.model_selection import train_test_split
  12. from keras.models import Model, load_model
  13. from keras.layers import Input, Dense,LeakyReLU,BatchNormalization
  14. from keras.callbacks import ModelCheckpoint
  15. from keras import regularizers
  16. from sklearn.preprocessing import StandardScaler
  17. from sklearn.metrics import roc_curve, auc, precision_recall_curve
  18. # 工作空间设置
  19. os.chdir('/Users/wuzhengxiang/Documents/DataSets/CreditCardFraudDetection')
  20. os.getcwd()

数据读取和简单的特征工程

  1. # 读取数据
  2. d = pd.read_csv('creditcard.csv')
  3. # 查看样本比例
  4. num_nonfraud = np.sum(d['Class'] == 0)
  5. num_fraud = np.sum(d['Class'] == 1)
  6. plt.bar(['Fraud', 'non-fraud'], [num_fraud, num_nonfraud], color='dodgerblue')
  7. plt.show()
  8. # 删除时间列,对Amount进行标准化
  9. data = d.drop(['Time'], axis=1)
  10. data['Amount'] = StandardScaler().fit_transform(data[['Amount']])
  11. X = data.drop(['Class'],axis=1)
  12. Y = data.Class

基于深度学习Autoencoder的信用卡欺诈异常检测 - 图10
模型搭建+模型训练

  1. # 设置Autoencoder的参数
  2. input_dim = X.shape[1]
  3. encoding_dim = 128
  4. num_epoch = 30
  5. batch_size = 256
  6. input_layer = Input(shape=(input_dim, ))
  7. encoder = Dense(encoding_dim,
  8. activation="tanh",
  9. activity_regularizer=regularizers.l1(10e-5)
  10. )(input_layer)
  11. encoder =BatchNormalization()(encoder)
  12. encoder=LeakyReLU(alpha=0.2)(encoder)
  13. encoder = Dense(int(encoding_dim/2),
  14. activation="relu"
  15. )(encoder)
  16. encoder =BatchNormalization()(encoder)
  17. encoder=LeakyReLU(alpha=0.1)(encoder)
  18. encoder = Dense(int(encoding_dim/4),
  19. activation="relu"
  20. )(encoder)
  21. encoder =BatchNormalization()(encoder)
  22. ### decoder
  23. decoder = LeakyReLU(alpha=0.1)(encoder)
  24. decoder = Dense(int(encoding_dim/4),
  25. activation='tanh'
  26. )(decoder)
  27. decoder = BatchNormalization()(decoder)
  28. decoder = LeakyReLU(alpha=0.1)(decoder)
  29. decoder = Dense(int(encoding_dim/2),
  30. activation='tanh'
  31. )(decoder)
  32. decoder = BatchNormalization()(decoder)
  33. decoder = LeakyReLU(alpha=0.1)(decoder)
  34. decoder = Dense(input_dim,
  35. #activation='relu'
  36. )(decoder)
  37. autoencoder = Model(inputs = input_layer,
  38. outputs = decoder
  39. )
  40. autoencoder.compile(optimizer='adam',
  41. loss='mean_squared_error',
  42. metrics=['mae','mse']
  43. )
  44. # 模型保存为 XiaoWuGe_model.h5,并开始训练模型
  45. checkpointer = ModelCheckpoint(filepath="XiaoWuGe_model.h5",
  46. verbose=0,
  47. save_best_only=True
  48. )
  49. history = autoencoder.fit(X,
  50. X,
  51. epochs=num_epoch,
  52. batch_size=batch_size,
  53. shuffle=True,
  54. #validation_data=(X_test, X_test),
  55. verbose=1,
  56. callbacks=[checkpointer]
  57. ).history
  58. Epoch 1/30
  59. 284807/284807 [==============================] - 39s 136us/step - loss: 0.6593 - mae: 0.3893 - mse: 0.4098
  60. Epoch 2/30
  61. Epoch 29/30
  62. 284807/284807 [==============================] - 41s 144us/step - loss: 0.1048 - mae: 0.1188 - mse: 0.0558
  63. Epoch 30/30
  64. 284807/284807 [==============================] - 39s 135us/step - loss: 0.0891 - mae: 0.1134 - mse: 0.0495
  65. 模型结果可视化
  66. # 画出损失函数曲线
  67. plt.figure(figsize=(14, 5))
  68. plt.subplot(121)
  69. plt.plot(history['loss'], c='dodgerblue', lw=3)
  70. plt.title('model loss')
  71. plt.ylabel('mse')
  72. plt.xlabel('epoch')
  73. plt.legend(['train'], loc='upper right')
  74. # 画出损失函数曲线
  75. plt.figure(figsize=(14, 5))
  76. plt.subplot(121)
  77. plt.plot(history['mae'], c='dodgerblue', lw=3)
  78. plt.title('model mae')
  79. plt.ylabel('mae')
  80. plt.xlabel('epoch')
  81. plt.legend(['train'], loc='upper right')
  82. # 画出损失函数曲线
  83. plt.figure(figsize=(14, 5))
  84. plt.subplot(121)
  85. plt.plot(history['mse'], c='dodgerblue', lw=3)
  86. plt.title('model mse')
  87. plt.ylabel('mse')
  88. plt.xlabel('epoch')
  89. plt.legend(['train'], loc='upper right')

基于深度学习Autoencoder的信用卡欺诈异常检测 - 图11
模型结果预测

  1. #利用训练好的autoencoder重建测试集
  2. pred_X = autoencoder.predict(X)
  3. # 计算还原误差MSE和MAE
  4. mse_X = np.mean(np.power(X-pred_X,2), axis=1)
  5. mae_X = np.mean(np.abs(X-pred_X), axis=1)
  6. data['mse_X'] = mse_X
  7. data['mae_X'] = mae_X
  8. # TopN准确率评估
  9. n = 1000
  10. df = data.sort_values(by='mae_X',ascending=False)
  11. df = df.head(n)
  12. rate = df[df['Class']==1].shape[0]/n
  13. print('Top{}的准确率为:{}'.format(n,rate))
  14. Top1000的准确率为:0.336

可以看到,我们的准确率为0.336,比之前的孤立森林又有了很大的提高,但是我经过了比较多的试验,这是比较理想的结果。后期我会找个更加稳定的结构分享给大家,下面我可以可以看看,正样本和负样本的一个分布差异。

  1. # 提取负样本,并且按照7:3切成训练集和测试集
  2. mask = (data['Class'] == 0)
  3. X_train, X_test = train_test_split(X, test_size=0.3,
  4. random_state=520)
  5. # 提取所有正样本,作为测试集的一部分
  6. X_fraud = X[~mask]
  7. # 利用训练好的autoencoder重建测试集
  8. pred_test = autoencoder.predict(X_test)
  9. pred_fraud = autoencoder.predict(X_fraud)
  10. # 计算还原误差MSE和MAE
  11. mse_test = np.mean(np.power(X_test - pred_test, 2), axis=1)
  12. mse_fraud = np.mean(np.power(X_fraud - pred_fraud, 2), axis=1)
  13. mae_test = np.mean(np.abs(X_test - pred_test), axis=1)
  14. mae_fraud = np.mean(np.abs(X_fraud - pred_fraud), axis=1)
  15. mse_df = pd.DataFrame()
  16. mse_df['Class'] = [0] * len(mse_test) + [1] * len(mse_fraud)
  17. mse_df['MSE'] = np.hstack([mse_test, mse_fraud])
  18. mse_df['MAE'] = np.hstack([mae_test, mae_fraud])
  19. mse_df = mse_df.sample(frac=1).reset_index(drop=True)
  20. # 分别画出测试集中正样本和负样本的还原误差MAE和MSE
  21. markers = ['o', '^']
  22. markers = ['o', '^']
  23. colors = ['dodgerblue', 'red']
  24. labels = ['Non-fraud', 'Fraud']
  25. plt.figure(figsize=(14, 5))
  26. plt.subplot(121)
  27. for flag in [1, 0]:
  28. temp = mse_df[mse_df['Class'] == flag]
  29. plt.scatter(temp.index,
  30. temp['MAE'],
  31. alpha=0.7,
  32. marker=markers[flag],
  33. c=colors[flag],
  34. label=labels[flag])
  35. plt.title('Reconstruction MAE')
  36. plt.ylabel('Reconstruction MAE')
  37. plt.xlabel('Index')
  38. plt.subplot(122)
  39. for flag in [1, 0]:
  40. temp = mse_df[mse_df['Class'] == flag]
  41. plt.scatter(temp.index,
  42. temp['MSE'],
  43. alpha=0.7,
  44. marker=markers[flag],
  45. c=colors[flag],
  46. label=labels[flag])
  47. plt.legend(loc=[1, 0], fontsize=12)
  48. plt.title('Reconstruction MSE')
  49. plt.ylabel('Reconstruction MSE')
  50. plt.xlabel('Index')
  51. plt.show()

基于深度学习Autoencoder的信用卡欺诈异常检测 - 图12
可以看到,正负样本的MAE和MSE有比较明显的差异,证明这个算法有很好的异常检测能力,当然,有部分正常样本还是很难通过异常检测分开。