Anomaly Detection异常检测的几种方法

异常检测首先要先根据业务情况确定什么是异常数据,再选择合适的方法进行算法实现。通常来说可以考虑如下几种方法:

  1. PCA主成分分析
  2. Isolation Forest
  3. Autoencoder
  4. Classification

1.PCA主成分分析在上一篇文里写过了

  1. Isolation Forest其实很简单,可以理解为无监督的随机森林算法。他的基本原理是利用树模型把数据进行分割,一直分到只有一个独立点为止。越快分割成单独数据点,说明这个数据越异常。
model = IsolationForest(n_jobs=8, contamination=ATTACK_FRACTION, max_features=8, n_estimators=1024)
#Define train data
train_data = get_train_data(df_full)
#Fit model
model.fit(train_data[numeric_features])

results = model.predict(X[numeric_features])
results = (results == -1)
  1. Autoencoder
    先引用一篇英文博客,写得很全面,并且提供了代码,下面内容主要是搬运工!https://medium.com/@curiousily/credit-card-fraud-detection-using-autoencoders-in-keras-tensorflow-for-hackers-part-vii-20e0c85301bd
    传统的维度下降依赖于线性方法,如 PCA,找出高维数据中最大的方差的方向。通过选择这些方向,PCA 本质上刻画了包含了最终信息的方向。所以我们可以找到一个较小的维度的数目来作为降维的结果。然而,PCA 方法的线性性也是导致自身可以抽取出的特征维度类型上的很大限制。Autoencoder通过引入神经网络天生的非线性性克服这些限制。
    Screen Shot 2018-09-04 at 10.54.30 PM.png

步骤主要是:
3.0

import pandas as pd
import numpy as np
import pickle
import matplotlib.pyplot as plt
from scipy import stats
import tensorflow as tf
import seaborn as sns
from pylab import rcParams
from sklearn.model_selection import train_test_split
from keras.models import Model, load_model
from keras.layers import Input, Dense
from keras.callbacks import ModelCheckpoint, TensorBoard
from keras import regularizers

%matplotlib inline

sns.set(style='whitegrid', palette='muted', font_scale=1.5)

rcParams['figure.figsize'] = 14, 8

RANDOM_SEED = 42
LABELS = ["Normal", "Fraud"]

3.1 把data去掉label,进行标准化处理。

from sklearn.preprocessing import StandardScaler
data = df.drop(['Time'], axis=1)
data['Amount'] = StandardScaler().fit_transform(data['Amount'].values.reshape(-1, 1))

3.2 数据切分,分成x_train, x_test, y_test. 注意在训练的时候只用x_train, 不需要y_train当label, 因为这是一种无监督的学习方法

X_train, X_test = train_test_split(data, test_size=0.2, random_state=RANDOM_SEED)
X_train = X_train[X_train.Class == 0]
X_train = X_train.drop(['Class'], axis=1)

y_test = X_test['Class']
X_test = X_test.drop(['Class'], axis=1)

X_train = X_train.values
X_test = X_test.values

3.3 建模

input_dim = X_train.shape[1]
encoding_dim = 14
input_layer = Input(shape=(input_dim, ))

encoder = Dense(encoding_dim, activation="tanh", 
                activity_regularizer=regularizers.l1(10e-5))(input_layer)
encoder = Dense(int(encoding_dim / 2), activation="relu")(encoder)

decoder = Dense(int(encoding_dim / 2), activation='tanh')(encoder)
decoder = Dense(input_dim, activation='relu')(decoder)

autoencoder = Model(inputs=input_layer, outputs=decoder)

训练模型

nb_epoch = 100
batch_size = 32

autoencoder.compile(optimizer='adam', 
                    loss='mean_squared_error', 
                    metrics=['accuracy'])

checkpointer = ModelCheckpoint(filepath="model.h5",
                               verbose=0,
                               save_best_only=True)
tensorboard = TensorBoard(log_dir='./logs',
                          histogram_freq=0,
                          write_graph=True,
                          write_images=True)

history = autoencoder.fit(X_train, X_train,
                    epochs=nb_epoch,
                    batch_size=batch_size,
                    shuffle=True,
                    validation_data=(X_test, X_test),
                    verbose=1,
                    callbacks=[checkpointer, tensorboard]).history

3.4 用模型计算输出X与输入X相比较的误差。这里的预测结果并不是我们最终想要的label,而是跟输入的X矩阵一样形状的数据集。我们需要对这个输出集求error集合。

predictions = autoencoder.predict(X_test)
mse = np.mean(np.power(X_test - predictions, 2), axis=1)
error_df = pd.DataFrame({'reconstruction_error': mse,
                        'true_class': y_test})
error_df.describe()

3.5 进一步预测
模型本身并不知道如何预测新的数据是被归为0还是1。我们通过上一步计算了重构误差,在这一步则需要自定义一个合理的阈值,以此为基础判断3.4步骤里由模型算出来的误差,如果error大于阈值,则归为1,否则归为0。

threshold = defined_number # 这里需要主观定义,但可以用sklearn的metrics模块通过画图做到心中有数。
groups = error_df.groupby('true_class')
fig, ax = plt.subplots()

for name, group in groups:
    ax.plot(group.index, group.reconstruction_error, marker='o', ms=3.5, linestyle='',
            label= "Fraud" if name == 1 else "Normal")
ax.hlines(threshold, ax.get_xlim()[0], ax.get_xlim()[1], colors="r", zorder=100, label='Threshold')
ax.legend()
plt.title("Reconstruction error for different classes")
plt.ylabel("Reconstruction error")
plt.xlabel("Data point index")
plt.show();
Screen Shot 2018-09-04 at 11.22.34 PM.png

当然也可以画出混淆矩阵来量化模型效果:

y_pred = [1 if e > threshold else 0 for e in error_df.reconstruction_error.values]
conf_matrix = confusion_matrix(error_df.true_class, y_pred)

plt.figure(figsize=(12, 12))
sns.heatmap(conf_matrix, xticklabels=LABELS, yticklabels=LABELS, annot=True, fmt="d");
plt.title("Confusion matrix")
plt.ylabel('True class')
plt.xlabel('Predicted class')
plt.show()

另外,以上几种方法,都可能会面临数据不平衡的问题,即class imbalance. 比如训练集中的异常数据比例及少,这种时候机器学习的模型可能算出来的Accuracy很好,但是实际上却是无效的。这种情况下有两个层面的解决:

数据层面的考虑:

  1. 扩大数据集。
  2. 采样数据。
    随机过采样(Over-Sampling)通过随机复制少数类来增加其实例数量。缺点是过拟合,优点是不会有信息丢失,表现好于下采样。这里面又有升级版的SMOTE(Synthetic Minority Over-sampling Technique)方法。
    随机欠采样(Under-Sampling)通过随机地消除占多数的类的样本来平衡类分布,直到多数类和少数类的实例实现平衡,目标才算达成。优点是针对大数据量可以解决存储问题,提升运行时间。缺点是去掉了一些信息,结果可能不精确。

模型层面的考虑:

  1. sklearn grid search调参的时候避免采用默认的accuracy score做指标,而改为F或precision。关于如何自定义模型评价指标可以看官网http://scikit-learn.org/stable/modules/model_evaluation.html
  2. 修改现有的分类算法,使其适用于不平衡数据集。主要考虑bagging和boosting模型。
    bagging: 一个最简单的集成方法就是不断从多数类中抽取样本,使得每个模型的多数类样本数量和少数类样本数量都相同,最后将这些模型集成起来。集成方法的主要目的是提高单个分类器的性能。该方法从原始数据中构建几个两级分类器,然后整合它们的预测。
    bagging关注在减小方差/克服过拟合,比如RF每一个树都是很深的深度,所以每一个树都有低偏差。投票之后,树越多,就可以让方差也越低。优点是在嘈杂的数据环境下,它性能优于boosting。缺点是bagging只在基分类器效果很好时才有效,错误的分类可能会进一步降低表现。

boosting的基分类器是弱学习器,即预测准确度仅略好于平均水平,每一个分类器方差低但偏差高。每一轮迭代都在上一个弱分关器的基础上调整权重,以达到总体集成分类器可以更好的fit样本,所以其目标是使总体的偏差降低。
按发明先后时间来介绍Adboost, Gradient Boosting, XGBoost:
Adboost最早,可以泛化得很好,适合分类问题且不易过拟合但是对嗓声数据敏感。
GBDT里的树都是回归树,不能是分类树,因为它的核心是每一棵树学的是之前所有树结论和的残差,这个残差就是一个加预测值后能得真实值的累加量。那么哪里体现了Gradient呢?并没有用到求导的梯度,只是用残差作为全局最优的绝对方向,这就是Gradient。GBDT的缺点是不好拟合。
XGboost是GB的更先进的实现,它对目标函数做了二阶导,并使用正则化和特征分块存储并行处理。优点是速度快。

参考:更全的具体问题和解决方法在这篇博文里有很好的阐述:https://flystarhe.github.io/docs-2014/algorithm/imbalanced-classification/readme/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • 首页 资讯 文章 资源 小组 相亲 登录 注册 首页 最新文章 IT 职场 前端 后端 移动端 数据库 运维 其他...
    Helen_Cat阅读 3,843评论 1 10
  • 查看原文 1 简介 Deep Learning最简单的一种方法是利用人工神经网络的特点,人工神经网络(ANN)本身...
    JinkeyAI阅读 6,732评论 0 4
  • 五、Deep Learning的基本思想 假设我们有一个系统S,它有n层(S1,…Sn),它的输入是I,输出是O,...
    dma_master阅读 1,616评论 1 2
  • 1 对多租户的理解 多租户定义:多租户技术或称多重租赁技术,简称SaaS,是一种软件架构技术,是实现如何在多用户环...
    Bobby0322阅读 25,799评论 3 29
  • 玫瑰园本期主题作业:漫步 本期作业主持人:云中飘舞 原创基地 漫步,是一种释放,也是一种心情,在阳光下漫步,和灿烂...
    云中飘舞阅读 511评论 2 17