用自编码器实现信用卡数据集的异常检测(详细),Pytorch版本

1.自动编码器(Auto encoder)

自动编码器(au toencoder) 是神经网络的一种,该网络可以看作由两部分组成:一个编码器和一个生成重构的解码器)。传统上,自动编码器被用于降维或特征学习。其为非线性降维,传统的如:PCA,为线性降维。

自编码器结构如下图所示,编码器来实现维度的压缩,解码器实现维度的恢复重构。

自编码器可用于:训练深度学习网络、压缩、分类以及异常检测等,本文主要是异常检测的应用。

 2.数据集

本文采用公开数据集,信用卡用户的异常检测。链接如下:链接:https://pan.baidu.com/s/16-OMOjF6-S-d704FgfshbA 
提取码:aaaa

 上图为数据集的大概。数据共有31列,其中最后一列为异常的标定,0为正常,1为异常。

3.数据预处理

首先导入所需要的库函数。

import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt
from torch.utils.data import DataLoader,TensorDataset
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import pandas as pd
from matplotlib import font_manager
import seaborn as sns

载入数据并对数据预处理

#加载数据并预处理
df = pd.read_csv(r'C:\Users\google1\PycharmProjects\pythonProject\Y异常检测案例\creditcard.csv')
df['Amount'] = StandardScaler().fit_transform(df['Amount'].values.reshape(-1,1))
features = df.columns[:-1].tolist()
df0 = df.query('Class==0').sample(40000)
df1= df.query('Class==1')
x_nom = df0
x_nov = df1

数据共有280000多行,其中正常数据有280000行,异常数据共有500个左右,选择40000个正常数据集和所有异常数据集,并将Amount列数据标准化。

#划分训练集和测试集
x_train, x_nom_test = train_test_split(x_nom.drop(labels=['Time','Class'],axis=1), train_size = 0.85, random_state = 1)
x_test = np.concatenate([x_nom_test,x_nov.drop(labels=['Time','Class'],axis=1)],axis = 0)
y_test = np.concatenate([np.zeros(len(x_nom_test)),np.ones(len(x_nov))])

划分数据集将85%的正常数据集作为训练集,将15%的正常数据集和异常数据集作为测试集。

#做数据格式的改变到张量
x_train = np.array(x_train)
x_test = np.array(x_test)

x_train,x_test = torch.FloatTensor(x_train),torch.FloatTensor(x_test)

#将训练数据处理为数据加载器
train_set = TensorDataset(x_train)
train_loader = DataLoader(dataset=train_set, batch_size=64, shuffle=True)

处理数据格式为张量,并将其读入加载器。

encoding_dim = 12
input_dim = x_train.shape[1]
class AutoEncoder(torch.nn.Module):
    def __init__(self):
        super(AutoEncoder, self).__init__()
        self.encoder = torch.nn.Sequential(
            torch.nn.Linear(input_dim,encoding_dim),
            torch.nn.ReLU(),
        torch.nn.Linear(encoding_dim,4),
        torch.nn.ReLU())
        self.decoder = torch.nn.Sequential(
            torch.nn.Linear(4,encoding_dim),
            torch.nn.ReLU(),
            torch.nn.Linear(encoding_dim, input_dim)
        )

    def forward(self, input):
        output = self.encoder(input)
        output = self.decoder(output)
        return output

定义自编码器网络结构,这里采用最简单的自动编码器。

4训练以及测试结果

  model = AutoEncoder()


    num_epochs = 50#选用50个epoch
    optimizer = torch.optim.Adam(model.parameters(), 0.001)
    loss_func = nn.MSELoss()#采用均方差损失函数
    all_loss = []
    for epoch in range(num_epochs):
        total_loss = 0
        for step, (x,) in enumerate(train_loader):
            x_recon = model(x)
            loss = loss_func(x_recon, x)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

            total_loss += loss.item() * len(x)
        total_loss /= len(train_set)
        all_loss.append(total_loss)

        # print('Epoch {}/{} : loss: {:.4f}'.format(
        #     epoch + 1, num_epochs, loss.item()))
    plt.figure(figsize=(12, 6))
    plt.plot(range(num_epochs),all_loss)
    plt.show()

损失可视化如下:

    def get_recon_err(X):
        return torch.mean((model(X) - X) ** 2, dim=1).detach().numpy()

    recon_err_train = get_recon_err(x_train)
    recon_err_test = get_recon_err(x_test)
    recon_err = np.concatenate([recon_err_train, recon_err_test])
    labels = np.concatenate([np.zeros(len(recon_err_train)), y_test])
    index = np.arange(0, len(labels))

    sns.kdeplot(recon_err[labels == 0], shade=True)
    sns.kdeplot(recon_err[labels == 1], shade=True)
    plt.show()

定义其重构误差这里采用平方均值来表示误差,并将异常和正常数据的误差密度可视化

 蓝色为正常数据的,橙色为正常数据

最后设置不同阈值,寻找最佳的划定阈值。

 threshold = np.linspace(0, 10, 200)
    acc_list = []
    f1_list = []
   
    for t in threshold:
        y_pred = (recon_err_test > t).astype(np.int)
        acc_list.append(accuracy_score(y_pred, y_test))
        f1_list.append(f1_score(y_pred, y_test))

    plt.figure(figsize=(8, 6))
    plt.plot(threshold, acc_list, c='y', label='acc')
    plt.plot(threshold, f1_list, c='b', label='f1')
    plt.xlabel('threshold')
    plt.ylabel('classification score')
    plt.legend()
    plt.show()


    i = np.argmax(f1_list)
    t = threshold[i]
    score = f1_list[i]
    print('threshold: %.3f,  f1 score: %.3f' % (t, score))

最后编写绘制画混淆矩阵的函数,可以调用绘制出异常检测的混淆矩阵以及异常和正常点的分类。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix, roc_auc_score
import seaborn as sns
from sklearn.preprocessing import MinMaxScaler


class visualization:
    labels = ["Noramal", "Anomaly"]

    def draw_confusion_matrix(self, y, ypred):
        matrix = confusion_matrix(y, ypred)

        plt.figure(figsize=(10, 8))
        colors = ["orange", "green"]
        sns.heatmap(matrix, xticklabels=self.labels, yticklabels=self.labels, cmap=colors, annot=True, fmt="d")
        plt.title("Confusion Matrix")
        plt.ylabel('Actual')
        plt.xlabel('Predicted')
        plt.show()

    def draw_anomaly(self, y, error, threshold):
        groupSDF = pd.DataFrame({'error': error,
                                 'true': y}).groupby('true')
        figure, axes = plt.subplots(figsize=(12, 8))

        for name, group in groupSDF:
            axes.plot(group.index, group.error, marker='x' if name == 1 else 'o', linestyle='',
                      color='r' if name == 1 else 'g', label="Anomaly" if name == 1 else "Normal")

        axes.hlines(threshold, axes.get_xlim()[0], axes.get_xlim()[1], colors='b', zorder=100, label="Threshold")
        axes.legend()

        plt.title("Anomalies")
        plt.ylabel("Error")
        plt.xlabel("Data")
        plt.show()

    def draw_error(self, error, threshold):
        plt.plot(error, marker='o', ms=3.5, linestyle='', label='Point')
        plt.hlines(threshold, xmin=0, xmax=len(error) - 1, colors='b', zorder=100, label='Threshold')
        plt.legend()
        plt.title("Reconstruction error")
        plt.ylabel("Error")
        plt.xlabel("Data")
        plt.show()
    import draw
    viz = draw.visualization()
    viz.draw_confusion_matrix(y_test,y_pred)
    viz.draw_anomaly(y_test,recon_err_test,threshold[i])

绘制混淆矩阵和分类可视化,其中选取使f1分数最大的阈值来实现

 

 

 由于数据集前面部分都是正常标签值,最后顺序的为异常值,现在将其排序打乱并重新可视化。

    c = list(zip(y_test, y_pred,recon_err_test))
    random.Random(100).shuffle(c)
    y_test, y_pred, recon_err_test = zip(*c)

将大部分异常值都分类出来,由于仅选用最简单的自编码器故其效果不是特别好,可尝试其他种类的自编密码器如VAE等。

  • 14
    点赞
  • 93
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
背景描述 本项目采用了UCI数据仓库,这是一个自1970年代中期以来广泛使用的公认资源。它在学术界享有盛誉,因其数据集涵盖了从生物信息学到社会科学等多个领域的真实世界问题,确保了研究成果的实用性和相关性。我们可以通过 Python 中的 ucimlrepo 库直接访问这些数据集,这样显著提高了数据获取的效率,简化了预处理流程,从而让我们能够迅速投入到实证分析中去。 而且还有还很重要的一点:该数据集的普及性和熟悉度为我们的研究提供了一个共同的基准,使得方法论的通用性和比较性得到加强。同时,数据的真实性和可复刻性也为项目带来了额外的价值。我们的分析不仅可以由同行学者验证,而且还可以促进知识的积累,为未来的科学探索提供基石。这种方法论和数据来源的选择可以确保你的项目或者算法能够在数据科学界得到广泛的认可和应用。 数据说明 这份数据是 uci 数据仓库中的 Default of credit card clients 数据集。读取方法可以参考我的相关项目。 该数据集包含 30,000 名客户及其在台湾一家银行的信用卡交易数据。除了客户的静态特征外,该数据集还包含某年4月至9月的信用卡账单支付历史,以及客户信用卡的余额限制。目标是客户是否会在接下来的一个月,即该年10月拖欠信用卡付款。 ID:信用卡客户ID号 LIMIT_BAL:以新台币计算的信贷金额(包括个人和家庭/补充信贷)/ 信用卡限额 SEX: 性别 (1代表男性,2代表女性) EDUCATION:受 教育程度(1=研究生, 2=大学, 3=高中, 4=其他 5=未知, 6=未知) MARRIAGE:婚姻状况(1=已婚,2=单身,3=其他) AGE:年龄 X1:信用额度,包括其个人和家庭补充信用 X2:性别(1=male;2=female) X3:教育(1=研究生,2=大学,3=高中,4=其他) X4:婚姻状况(1=已婚,2=单身,3=其他) X5:年龄,age X6-X11:过去六个月的还款情况。X6-X11为9-4月的还款情况。其中,-1,代表按时还款;1,代表延时一个月还款;2,代表延时两个月还款.......依次类推,XN=n,代表延时n个月还款, X12-X17:过去六个月的账单数额情况。X12-X17为9-4月账单数额情况 X18-X23:过去六个月的还款数额情况。 X18-X23为9-4月还款数额情况 Y:目标属性,客户下个月还款违约情况(1=逾期,0=未逾期) 通常会用于分类模型,应用场景十分广泛。尤其适用于金融机构在风险评估和信贷审批过程中,以判断客户是否有资格获得其他贷款产品,例如汽车贷款。通过包含的23个输入变量,如信用额度、性别、教育程度等,以及目标变量,即客户的还款违约情况,研究者能够对信用风险进行准确评估。这些细致的数据为研究者提供了理解和预测客户行为的全面视角。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值