Prophet异常检测使用了Prophet时间序列预测。基本的Prophet模型是一个可分解的单变量时间序列模型,结合了趋势、季节性和节假日效应。
该模型预测还包括一个围绕估计的趋势部分的不确定性区间。
另外,完全的贝叶斯推断也可以以增加计算量为代价。然后,不确定性区间的上限和下限值可以作为每个时间点的离群点阈值。
在时间序列分析领域,有一种常见的分析方法叫做时间序列的分解(Decomposition of Time Series),它把时间序列 分成几个部分,分别是季节项 ,趋势项 ,剩余项 。也就是说对所有的 ,都有
除了加法的形式,还有乘法的形式,也就是:
以上式子等价于 。所以,有的时候在预测模型的时候,会先取对数,然后再进行时间序列的分解,就能得到乘法的形式。在 fbprophet 算法中,作者们基于这种方法进行了必要的改进和优化。
一般来说,在实际生活和生产环节中,除了季节项,趋势项,剩余项之外,通常还有节假日的效应。所以,在 prophet 算法里面,作者同时考虑了以上四项,也就是:
其中 表示趋势项,它表示时间序列在非周期上面的变化趋势; 表示周期项,或者称为季节项,一般来说是以周或者年为单位; 表示节假日项,表示在当天是否存在节假日; 表示误差项或者称为剩余项。Prophet 算法就是通过拟合这几项,然后最后把它们累加起来就得到了时间序列的预测值。
趋势项模型
在 Prophet 算法里面,趋势项有两个重要的函数,一个是基于逻辑回归函数(logistic function)的,另一个是基于分段线性函数(piecewise linear function)的。
首先,我们来介绍一下基于逻辑回归的趋势项是怎么做的。
如果回顾逻辑回归函数的话,一般都会想起这样的形式: 它的导数是 并且 如果增加一些参数的话,那么逻辑回归就可以改写成:
这里的 称为曲线的最大渐近值, 表示曲线的增长率, 表示曲线的中点。当 时,恰好就是大家常见的 sigmoid 函数的形式。从 sigmoid 的函数表达式来看,它满足以下的微分方程: 。
那么,如果使用分离变量法来求解微分方程 就可以得到:
但是在现实环境中,函数 的三个参数 不可能都是常数,而很有可能是随着时间的迁移而变化的,因此,在 Prophet 里面,作者考虑把这三个参数全部换成了随着时间而变化的函数,也就是
除此之外,在现实的时间序列中,曲线的走势肯定不会一直保持不变,在某些特定的时候或者有着某种潜在的周期曲线会发生变化,这种时候,就有学者会去研究变点检测,也就是所谓 change point detection。
方法
首先,计算从观测值到最近的不确定度边界(上限或下限)的距离。如果观察值在边界内,离群点得分等于负距离。
因此,当观测值与模型预测值相等时,离群点得分最低。如果观察值在边界之外,得分等于距离测量,观察值被标记为离群点。然而,该方法的一个主要缺点是,当新的数据进来时,你需要重新调整模型。这对于具有实时检测的应用来说是不可取的。
数据集
这个例子使用了地球化学研究所记录的天气时间序列数据集。该数据集包含14个不同的特征,如空气温度、大气压力和湿度。这些都是在2003年开始,每10分钟收集一次。我们只使用2009年至2016年期间收集的数据。
import matplotlib.pyplot as plt
import numpy as np
import os
import pandas as pd
import tensorflow as tf
加载数据集
df = pd.read\_csv(csv\_path)
df\['Date Time'\] = pd.to_datetime(df\['Date Time'\], format='%d.%m.%Y %H:%M:%S')
df.head()
选择子集来测试Prophet模型。
``````
n_prophet = 10000
Prophet模型需要得到一个有两列的DataFrame:一列名为ds,包含时间戳,一列名为y,包含要评估的时间序列。我们只看温度数据。
print(df_T.shape)
df_T.head()
plt.plot(df\_T\['ds'\], df\_T\['y'\])
加载或定义离群检测
你可以将预训练的模型保存在本地目录的文件路径中,并加载检测模型。或者,你也可以从头开始训练一个检测模型。
filepath = 'my_path' # 改为下载模型的目录
if outlier_detector: # 加载预训练的离群检测器
filepath = os.path.join(filepath, detector_name)
else: # 初始化、拟合并保存离群检测
od.fit(df_T)
请查看文档以及原始的Prophet文档,了解如何定制基于Prophet的异常值检测器,并添加季节性因素、假期、选择饱和逻辑增长模型或应用参数正则化。
预测测试数据中的异常值
定义测试数据。重要的是,测试数据的时间与训练数据一致。下面我们通过比较测试数据框的前几行和训练数据框的最后几行来检查这一点。
df\_T\_test = pd.DataFrame(data=d)
随时关注您喜欢的主题
df_T.tail()
预测测试数据的异常值。
predict(
df\_T\_test
)
结果可视化
我们可以用Prophet将我们的预测结果可视化。包括历史预测。
model.predict(future)
model.plot(forecast)
我们还可以绘制预测中不同成分的细分。预测的不确定性区间是由外推趋势的MAP估计值决定的。
plot_component(forecast)
很明显,我们对未来的预测越远,决定离群值阈值的不确定性区间就越大。
让我们把实际数据与离群点阈值的上限和下限预测值叠加起来,检查我们预测的离群点在哪里。
plot(x='ds', y=\['y', 'yhat', 'yhat\_upper', 'yhat\_lower'\])
异常点的得分和预测。
np.zeros(n_periods)
plot(x='ds', y=\['score', 'threshold'\])
当我们进一步预测未来时,随着不确定性的增加,离群点的分数自然呈下降趋势。
让我们来看看一些个别的离群值。
outlier = fcst.loc\[fcst\['score'\] > 0\]
print((outlier.shape\[0\]))
可下载资源
关于作者
Kaizong Ye是拓端研究室(TRL)的研究员。在此对他对本文所作的贡献表示诚挚感谢,他在上海财经大学完成了统计学专业的硕士学位,专注人工智能领域。擅长Python.Matlab仿真、视觉处理、神经网络、数据分析。
本文借鉴了作者最近为《R语言数据分析挖掘必知必会 》课堂做的准备。
非常感谢您阅读本文,如需帮助请联系我们!