异常检测3——AutoEncoder异常检测

参考论文:
An, Jinwon, and Sungzoon Cho. “Variational autoencoder based anomaly detection using reconstruction probability.” Special Lecture on IE 2.1 (2015): 1-18.

整体的算法思路

AutoEncoder的模型与pytorch建模可以参考:https://blog.csdn.net/weixin_35757704/article/details/118457110

  1. 将正常样本与异常样本切分为:训练集X,训练集Y,测试集X,测试集Y
  2. AutoEncoder建模:建模
  3. 用正样本数据训练AutoEncoder:因为AutoEncoder是要想办法复现原有数据,因此要确保AutoEncoder看到的都只是自身正常的数据,这样当异常的数据到来时,就会出现很突兀的状况,这也是我们要的效果。
  4. 计算阈值:这是很多研究讨论的点。因为异常样本会造成很突兀的效果,但是突兀的程度有多大,我们认为是异常样本,就是这里要明确的
  5. 让样本通过Autoencoder模型,复现后的Loss超过阈值,就被认为是异常样本,没有超过阈值则为正常样本

示例代码

在下面的代码中,步骤从上到下,通过def main()函数串联整个流程,Debug效果更加

import numpy as np
from pyod.utils.data import generate_data
import torch
import torch.nn as nn
import torch.utils.data as Data
from loguru import logger
from sklearn.metrics import accuracy_score, recall_score


# 步骤1:获取数据源
def get_data():
    """生成数据"""
    X_train, X_test, y_train, y_test = generate_data(
        n_train=10000, n_test=1000, n_features=50, contamination=0.2, behaviour='new')  # 这里生产数据
    return X_train, X_test, y_train, y_test


# 步骤2:AutoEncoder建模,这里根据自己的数据调整模型,AutoEncoder不是一个固定的模型
class AutoEncoder(nn.Module):
    def __init__(self, input_size, hidden_layer_size=32):
        super().__init__()
        self.hidden_layer_size = hidden_layer_size
        # 输入与输出的维度相同
        self.input_size = input_size
        self.output_size = input_size

        self.encode_linear = nn.Linear(self.input_size, hidden_layer_size)
        self.decode_linear = nn.Linear(hidden_layer_size, self.output_size)
        self.relu = nn.ReLU()
        self.sigmoid = nn.Sigmoid()

    def forward(self, input_x):
        # encode
        encode_linear = self.encode_linear(input_x)
        encode_out = self.sigmoid(encode_linear)
        # decode
        decode_linear = self.decode_linear(encode_out)  # =self.linear(lstm_out[:, -1, :])
        return decode_linear


# 步骤3:训练模型
def train_auto_encoder(normal_data: np.ndarray):
    """训练Auto Encoder模型"""
    train_tensor = torch.tensor(normal_data).float()
    batch_size = 20

    train_loader = Data.DataLoader(
        dataset=Data.TensorDataset(train_tensor),  # 封装进Data.TensorDataset()类的数据,可以为任意维度
        batch_size=batch_size,  # 每块的大小
        shuffle=True,  # 要不要打乱数据 (打乱比较好)
        num_workers=2,  # 多进程(multiprocess)来读数据
    )
    # 建模三件套:loss,优化,epochs
    model = AutoEncoder(train_tensor.shape[1])  # 模型
    loss_function = nn.MSELoss()  # loss
    optimizer = torch.optim.Adam(model.parameters(), lr=0.001)  # 优化器
    epochs = 30
    # 开始训练
    model.train()
    loss_list = []
    for i in range(epochs):
        epoch_loss_list = []
        for seq in train_loader:
            seq = seq[0]
            optimizer.zero_grad()
            y_pred = model(seq).squeeze()  # 压缩维度:得到输出,并将维度为1的去除
            single_loss = loss_function(y_pred, seq)
            single_loss.backward()
            optimizer.step()
            epoch_loss_list.append(single_loss.detach().numpy())
        logger.debug("Train Step:{} loss: {}", i, np.mean(epoch_loss_list))
        loss_list.append(np.mean(epoch_loss_list))
    return model, np.min(loss_list)


# 步骤4:模型训练完成,开始找正常数据与异常数据的阈值
def set_threshold(auto_encoder_model, error_data: np.ndarray, normal_loss):
    """阈值计算:这里通过正常数据的最小loss与最大异常的loss取中间值,作为阈值的loss"""
    error_tensor = torch.tensor(error_data).float()
    error_loader = Data.DataLoader(
        dataset=Data.TensorDataset(error_tensor),
        shuffle=True,
        num_workers=2,
    )
    loss_function = nn.MSELoss()
    error_loss = []
    auto_encoder_model.eval()
    for seq in error_loader:
        seq = seq[0]
        y_pred = auto_encoder_model(seq).squeeze()
        loss = loss_function(y_pred, seq)
        error_loss.append(loss.detach().numpy())
    threshold = (np.min(error_loss) - normal_loss) / 2
    logger.info("阈值计算完毕:正常样本的最大loss:{},异常样本的最小loss:{},阈值:{}", normal_loss, np.min(error_loss), threshold)
    return threshold


# 步骤5:异常检测
def anomaly_detection(auto_encoder_model, threshold, x_test, y_test):
    # 这里构建测试数据
    test_tensor = torch.tensor(x_test).float()
    test_loader = Data.DataLoader(
        dataset=Data.TensorDataset(test_tensor),
        shuffle=True,
        num_workers=2,
    )
    pred_list = []
    loss_function = nn.MSELoss()
    # 通过 Auto Encoder 模型进行预测
    auto_encoder_model.eval()
    for seq in test_loader:
        seq = seq[0]
        y_pred = auto_encoder_model(seq).squeeze()
        loss = loss_function(y_pred, seq)
        if loss < threshold:
            pred_list.append(0)
        else:
            pred_list.append(1)  # 异常
    # 评价指标
    logger.info("准确率:{} 召回率:{}", accuracy_score(y_test, pred_list), recall_score(y_test, pred_list))


def main():
    x_train, x_test, y_train, y_test = get_data()
    model, normal_loss = train_auto_encoder(x_train[y_train == 0])  # 拿正例数据进行训练
    threshold = set_threshold(model, x_train[y_train == 1], normal_loss)
    anomaly_detection(model, threshold, x_test, y_test)


if __name__ == '__main__':
    main()

打印的日志:

2022-03-25 16:22:45.409 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:0 loss: 7.666098117828369
2022-03-25 16:22:47.507 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:1 loss: 0.2303541898727417
2022-03-25 16:22:49.653 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:2 loss: 0.22991487383842468
2022-03-25 16:22:51.769 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:3 loss: 0.2299502193927765
2022-03-25 16:22:53.881 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:4 loss: 0.23001298308372498
2022-03-25 16:22:56.002 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:5 loss: 0.23006229102611542
2022-03-25 16:22:58.057 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:6 loss: 0.23018917441368103
2022-03-25 16:23:00.111 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:7 loss: 0.23030006885528564
2022-03-25 16:23:02.169 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:8 loss: 0.23039482533931732
2022-03-25 16:23:04.224 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:9 loss: 0.23047684133052826
2022-03-25 16:23:06.284 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:10 loss: 0.23054634034633636
2022-03-25 16:23:08.323 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:11 loss: 0.23061569035053253
2022-03-25 16:23:10.347 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:12 loss: 0.23073334991931915
2022-03-25 16:23:12.372 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:13 loss: 0.22996807098388672
2022-03-25 16:23:14.427 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:14 loss: 0.2291102260351181
2022-03-25 16:23:16.485 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:15 loss: 0.2279823124408722
2022-03-25 16:23:18.540 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:16 loss: 0.22661711275577545
2022-03-25 16:23:20.598 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:17 loss: 0.22481602430343628
2022-03-25 16:23:22.646 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:18 loss: 0.221832737326622
2022-03-25 16:23:24.710 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:19 loss: 0.2177421599626541
2022-03-25 16:23:26.776 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:20 loss: 0.21366573870182037
2022-03-25 16:23:28.779 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:21 loss: 0.2092127650976181
2022-03-25 16:23:30.764 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:22 loss: 0.2051170915365219
2022-03-25 16:23:32.736 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:23 loss: 0.19992759823799133
2022-03-25 16:23:34.755 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:24 loss: 0.19542557001113892
2022-03-25 16:23:36.771 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:25 loss: 0.1883782595396042
2022-03-25 16:23:38.757 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:26 loss: 0.1813327670097351
2022-03-25 16:23:40.760 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:27 loss: 0.17500406503677368
2022-03-25 16:23:42.744 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:28 loss: 0.16993017494678497
2022-03-25 16:23:44.727 | DEBUG    | __main__:train_auto_encoder:93 - Train Step:29 loss: 0.16403226554393768
2022-03-25 16:23:47.161 | INFO     | __main__:set_threshold:116 - 阈值计算完毕:正常样本的最大loss:0.16403226554393768,异常样本的最小loss:15.091814041137695,阈值:7.46389102935791
2022-03-25 16:23:49.223 | INFO     | __main__:anomaly_detection:142 - 准确率:0.694 召回率:0.235
### 企业信用数据分析中的异常检测 #### 方法概述 在企业信用数据分析中,异常检测旨在识别那些不符合常规模式的企业行为或财务状况。这些异常可能预示着潜在的风险因素,如违约风险增加、经营不善或是欺诈行为等。为了有效实施这一过程,可以采用多种先进的技术和算法。 对于企业信用数据而言,主要存在三类异常检测方法: - **监督学习法**:当有足够的标记样本可用时,可以通过训练模型区分正常与异常情况。例如逻辑回归和支持向量机都是常用的分类器,在此场景下能够帮助预测哪些公司更有可能出现问题[^2]。 - **无监督学习法**:如果缺乏足够的历史标签,则可考虑使用聚类分析(如K-means)、关联规则挖掘或者基于密度的空间聚类应用噪声处理(DBSCAN),后者尤其适合于发现形状复杂且大小各异的簇结构,并能很好地应对不同维度下的稀疏区域[^5]。 - **半监督学习法**:介于上述两者之间的情况也可以被纳入考量范围之内。这种方法适用于仅有少量已知类别实例的情形,它允许我们利用未标注的数据来增强模型的表现力。 除了传统的统计手段外,现代的人工智能技术也为解决此类问题提供了新的思路。特别是深度神经网络及其变体——自动编码器(Autoencoder),因其强大的特征提取能力而在众多实际案例中展现出优越性能[^3]。 #### 工具推荐 针对具体的技术实现方面,Python编程语言凭借其丰富的库资源成为首选平台之一。以下是几个值得推荐的相关工具包: -learn` 提供了一系列经典的机器学习算法接口,易于上手操作的同时也具备良好的灵活性; - `PyOD` 是专门为异常检测设计的一个开源项目,集成了超过二十种流行的算法并支持分布式计算环境; - 对于想要尝试更加前沿的研究成果者来说,还可以关注 TensorFlow 或 PyTorch 平台上的最新进展,比如 Variational Autoencoders(VAEs) 和 Generative Adversarial Networks(GANs)[^4]。 下面给出一段简单的代码片段展示如何借助 scikit-learn 中的 LOF 算法来进行初步探索: ```python from sklearn.neighbors import LocalOutlierFactor import pandas as pd # 假设 df 是包含了若干企业信用指标的时间序列 DataFrame 表格 df = pd.read_csv(&#39;credit_data.csv&#39;) lof = LocalOutlierFactor(n_neighbors=20, contamination=&#39;auto&#39;) y_pred = lof.fit_predict(df) outliers_index = np.where(y_pred == -1)[0] print(f"Detected {len(outliers_index)} outlier(s).") ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呆萌的代Ma

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值