利用LSTM和quantile regression(分位数回归)的异常行为检测

本文翻译自:Anomaly Detection with LSTM in Keras -- Marco Cerliani

目录

数据集

模型

交叉验证

结果

总结


“异常行为”(anomaly)的定义在不同的上下文中会有区别。在这种混乱中,我们可以知道:异常行为与我们感关注的领域密切相关。

异常检测在商业中是非常有用的,并且检测的难度取决于应用领域。如果遇到涉及人们活动的异常检测问题(例如对销售或需求的预测),则可以利用人们行为的基本假设,得到更有效的解决方案。

这正是我们在本文中所做的。我们尝试预测在不同时期纽约市的出租车需求。我们对人们的行为做了简单而重要的假设,可以帮助我们找到一种简单的方法来预测异常。所有麻烦的工作都是由Keras开发的LSTM进行的,它可以同时做预测和异常检测!

数据集

数据集是从Numenta社区获得的。我选择了纽约出租车数据集。此数据集每半小时观察一次,以显示2014–07–01至2015–01–31的纽约出租车需求

正常的一周
 

在此期间,根据与正常行为的偏离,存在5个异常值。它们分别在纽约马拉松,感恩节,圣诞节,元旦和暴风雪期间发生。

周异常值的例子:左为NY马拉松,右为圣诞节
​​​​

我们的目的是提前发现这些异常现象!

在查看数据时,我们注意到的第一个考虑因素是存在明显的每日模式(白天需求高于夜间)。出租车需求似乎也受到每周趋势的驱动:在一周的某些天,出租车需求高于其他需求。下面我们简单地证明了这种自相关关系(autocorrelation)

timeLags = np.arange(1,10*48*7)
autoCorr = [df.value.autocorr(lag=dt) for dt in timeLags]

plt.figure(figsize=(19,8))
plt.plot(1.0/(48*7)*timeLags, autoCorr)
plt.xlabel('time lag [weeks]')
plt.ylabel('correlation coeff', fontsize=12)
10周的自相关关系

现在,我们需要记录这些重要的行为以进行进一步的分析。我计算并存储每个星期几每个小时的平均值。当我们将数据标准化以建立模型,减少每种时间相关性时,这将会很有用(我将计算前5000个观测值的均值,这将成为我们将来的训练集)。

### CREATE WEEKDAY FEATURE AND COMPUTE THE MEAN FOR WEEKDAYS AT EVERY HOURS ###

df['weekday'] = df.timestamp.dt.weekday
df['weekday_hour'] = df.weekday.astype(str) +' '+ df.H.astype(str)
df['m_weekday'] = df.weekday_hour.replace(df[:5000].groupby('weekday_hour')['value'].mean().to_dict())

模型

我们需要一种可以提前发现异常值的策略。为此,我们决定关注出租车需求预测。我们希望开发一种模型,该模型能够在考虑不确定性的情况下预测需求。一种方法是发展分位数回归(quantile predictions)。我们专注于极值的预测:较低(第10个分位数),较高(第90个分位数)和经典第50个分位数。计算第90和第10分位数时,我们涵盖了现实中可以假设的最可能的值(绝大部分的值~80%的值应该在这个范围内出现)。这个范围的宽度(即置信区间Confidence Interval)可以很深;我们知道,当我们的模型能够确定未来时,它会很小;而当我们的模型无法看到关注领域中的重要变化时,它会变得非常大。我们利用这种行为,让我们的模型对出租车需求预测领域中的异常值检测进行了说明。当我们的模型对未来有把握时,我们期望会得到一个很小的间隔(置信区间很小),因为我们的模型认为他对预测结果很确定(under control)。另一方面,我们认为当间隔变大时会出现异常。因为我们的模型没有经过训练以处理这种可能导致异常的情况。(异常数值见到的不确定->置信区间变宽)

我们在Keras中构建一个简单的LSTM神经网络,可以神奇般地实现上面的过程。模型将接收过去的观察作为输入。我们调整了数据大小,以每日窗口大小作为LSTM的输入大小(48个观测值:每半小时一个观测值)。如上文所述,当我们生成数据时,我们进行了数据转换和标准化,减去了每日平均小时值,以便将观察结果视为其每日平均小时值的对数。我们以半小时轮班(half-hour shifting)的方式构建目标变量(我们希望预测接下来三十分钟的需求值,一步一步预测,即walk forward)。

inputs = Input(shape=(X_train.shape[1], X_train.shape[2]))
lstm = Bidirectional(LSTM(64, return_sequences=True, dropout=0.3))(inputs, training = True)
lstm = Bidirectional(LSTM(16, return_sequences=False, dropout=0.3))(lstm, training = True)
dense = Dense(50)(lstm)
out10 = Dense(1)(dense)
out50 = Dense(1)(dense)
out90 = Dense(1)(dense)
model = Model(inputs, [out10,out50,out90])

在Keras中进行分位数回归非常简单(我从这篇文章中学到了灵感)。我们可以很容易地自定义分位数损失函数,该函数根据分位数以及误差是正的(实际>预测)还是负的(实际<预测)对误差进行惩罚。我们的网络有3个输出和3个损失,每个输出和损失对应一个分位数。

def q_loss(q,y,f):
    e = (y-f)
    return K.mean(K.maximum(q*e, (q-1)*e), axis=-1)
losses = [lambda y,f: q_loss(0.1,y,f), lambda y,f: q_loss(0.5,y,f), lambda y,f: q_loss(0.9,y,f)]
model.compile(loss=losses, optimizer='adam', loss_weights = [0.3,0.3,0.3])

交叉验证

在Keras中处理神经网络时,比较烦银的问题之一是由于权重初始化而导致的结果不确定性。我们的例子也似乎遭受这种问题的困扰。比如计算分位数预测时,我们不允许分位数重叠!为了避免这种陷阱,我在预测阶段使用了bootstrapping:以及利用dropout在训练中,将预测迭代100次,将其存储起来,最后计算出所需的分位数(这种聪明的技术也在这篇文章中

pred_10, pred_50, pred_90 = [], [], []
NN = K.function([model.layers[0].input, K.learning_phase()], 
                [model.layers[-3].output,
                 model.layers[-2].output,
                 model.layers[-1].output])
for i in tqdm.tqdm(range(0,100)):
    predd = NN([X_test, 0.5])
    pred_10.append(predd[0])
    pred_50.append(predd[1])
    pred_90.append(predd[2])

下面以图形方式说明了此过程,只介绍了一部分预测。给定分位数bootstraps,我们计算了它们的汇总度量(红线),避免了交叉。

q90预测bootstraps(青色);q50预测bootstraps(蓝色);q10预测bootstraps(绿色)

结果

正如我之前所说的,我使用前5000个观察值进行训练,其余(大约5000个)观察值用于测试。

我们的模型在预测50位数的出租车需求方面达到了出色的性能。均方根对数误差(Mean Squared Log Error)约为0.055,是一个了不起的结果!这意味着LSTM网络能够理解出租车需求的基本规则。因此,我们的异常检测方法听起来很棒……我们计算了第90个分位数预测与第10个分位数预测之间的差值,然后看看发生了什么。

真实值(红色线);分位数区间长度(蓝色点)

在预测不确定的时候,分位数间隔(蓝点)较高。在其他情况下,正如我们所期望的那样,该模型有很好的泛化效果。我们注意到这些与我们最初的假设一致。下面绘制的橙色圆圈分别是:纽约马拉松,感恩节,圣诞节,元旦和暴风雪。

异常检测

我们达到了最初的目标:获得强大的预测能力,并利用模型的优势来识别不确定性。我们还利用它来实现异常检测。

总结

在这篇文章中,我为异常检测和预测提供了一个很好的解决方案。我们利用LSTM网络来了解纽约市出租车需求。我们利用所学的知识进行预测并同时估计不确定性。我们隐式地将异常定义为不可预测的观测值,即存在大量不确定性。这个简单的假设使我们的LSTM可以为我们完成所有工作。

 

本文代码notebook:

 https://github.com/cerlymarco/MEDIUM_NoteBook/blob/master/Anomaly_Detection_LSTM/Anomaly_Detection_LSTM.ipynb

评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值