ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

(三)比特币时间序列数据的AI异常检测

2021-06-26 22:03:01  阅读:482  来源: 互联网

标签:loss 比特 AI pano scaled test 序列 detector 异常


目录

介绍

了解异常

AI视角下的异常检测

使用K-Means聚类检测异常

实现神经网络和自动编码器来检测比特币历史价格的异常

下一步


介绍

本系列文章将指导您完成使用AI开发功能齐全的时间序列预测器和异常检测器应用程序所需的步骤。我们的预测器/检测器将处理加密货币数据,特别是比特币。但是,在学习完本系列之后,您将能够将学到的概念和方法应用于任何性质相似的数据类型。

要从本系列中充分受益,您应该具备一些Python、机器学习和Keras技能。整个项目都可以在我的“GitHub 存储库中找到。您还可以在此处此处查看完全交互式的notebook。

上一篇文章 中,您学习了如何准备时间序列数据以提供给机器学习 (ML) 和深度学习 (DL) 模型。在本文中,我将解释如何检测此类数据中的异常。

了解异常

您可能想知道什么是异常?你怎么能检测到它?是否真的有可能在尚未播放的场景中检测到异常情况?异常是一个流行的术语,指的是不规则的东西。在统计学中,异常通常被称为异常值——数据收集中的罕见或意外事件。如果数据集的分布近似正态,则异常将是与平均值相差2个标准差的所有数据点。

举例说明异常的概念:汽车发动机的温度必须低于90摄氏度,否则它会过热并发生故障。发动机的制冷系统使温度保持在安全范围内;如果失败,您可能会注意到非常高的温度值。从数学上讲,您的值会在很长一段时间内低于90,然后这些值会突然达到150,直到您的引擎崩溃。从表面上看,这就是我的意思:

您会看到70到90摄氏度之间的数据点,但图表末尾的不同值突然打破了模式(突出显示的那些)。这些后面的观察是异常值,因此是异常值。上图显示了描述异常的模式。

AI视角下的异常检测

现在你知道什么是异常了——你如何检测它?正如您可能推断的那样,异常检测是识别数据集合中意外项目或事件的过程——那些很少发生的项目或事件。异常检测有两种形式。一种是单变量异常检测,它是识别单个空间(单个变量)中值分布的那些意外数据点的过程。另一种是多变量异常检测,其中异常值是至少两个变量的异常分数的组合。

我将把这些系列的重点放在单变量异常检测上。但是,请注意,相同的方法可以作为更复杂模型的基线,旨在检测多变量上下文中的异常。

使用K-Means聚类检测异常

如果您已经检查了推荐的数据集,您会注意到它们根本没有标记,这意味着尚不清楚什么是异常,什么不是。这是您在实际案例中必须处理的典型场景。当您面临异常检测挑战时,您必须收集直接来自源的数据并应用某些技术来发现异常。这正是我们在无监督学习的帮助下要做的事情。无监督学习是一种机器学习,其中模型在未标记的数据上进行训练以发现模式。从理论上讲,它不需要人工干预来对数据进行分组,因此可以识别异常——如果这是要求的话。

请记住,K-Means聚类非常简单——当今最简单的聚类之一——但您会看到它有多么有用。K-Means Clustering是一种将相似数据点分组并找出肉眼不明显的潜在模式的算法。K——质心的数量——定义了在给定的数据集中必须识别多少组或集群。集群作为具有相似性的数据点的集合。从数学上讲,质心是集群的中心。

该算法通过随机选择K个质心作为每个簇的起点开始数据处理,然后迭代进行计算以优化质心位置。一旦确定了集群,算法就会将每个数据点分配到最近的集群,并为每个观察添加相应的标签。

让我们用一个基本的例子来形象化。TS假设您有X个随机值绘制如下:

您可以轻松识别两个集群:

简而言之,这就是K-Means聚类算法所做的。现在让我们看看这个算法如何在我们的数据集上工作。发出以下命令:

# Preparing data to be passed to the model
outliers_k_means = pano.copy()[51000:]
outliers_k_means.fillna(method ='bfill', inplace = True)
kmeans = KMeans(n_clusters=2, random_state=0).fit(outliers_k_means['Weighted_Price'].values.reshape(-1, 1))
outlier_k_means = kmeans.predict(outliers_k_means['Weighted_Price'].values.reshape(-1, 1))
outliers_k_means['outlier'] = outlier_k_means
outliers_k_means.head()

您将获得结果数据帧的前五行:

在上表中,“异常值”列中每行为0表示正常,而该列中每行为1表示异常。让我们绘制整个数据集以查看模型如何识别这些值:

a = outliers_k_means.loc[outliers_k_means['outlier'] == 1] #anomaly
 
fig = go.Figure()
fig.add_trace(go.Scatter(x=outliers_k_means['Weighted_Price'].index, y=outliers_k_means['Weighted_Price'].values,mode='lines',name='BTC Price'))
fig.add_trace(go.Scatter(x=a.index, y=a['Weighted_Price'].values,mode='markers',name='Anomaly',marker_symbol='x',marker_size=2))
fig.update_layout(showlegend=True,title="BTC price anomalies - KMeans",xaxis_title="Time",yaxis_title="Prices",font=dict(family="Courier New, monospace"))
fig.show()

上图非常符合实际的比特币价格现实,因为过去几周价格一直异常。该算法将13,000美元以上的值聚类为一个类别,将低于此阈值的值聚类为另一个类别。

实现神经网络和自动编码器来检测比特币历史价格的异常

现在让我们在神经网络 (NN) 的帮助下使用无监督学习技术。众所周知,这种方式对于异常检测更加灵活和准确。

如今,神经网络因其惊人的力量和出色的结果而成为新的规范。我们将以一种不同寻常的方式使用它们:我们将利用LSTM(长短期记忆) NN和自动编码器来构建无监督学习模型。这种方法的主要目标是改进上一个模型获得的结果,我计划通过对当前数据集的分布进行建模来实现这一点,以便更多地了解其结构。

一般来说,异常检测问题可以通过分类或回归来解决,这取决于数据集是否被标记。我们接下来要做的是将我们的数据集建模为一个回归问题,我们将在其中量化我们网络的重建误差。这实质上意味着我们将构建一个模型,该模型可以重建数据集中序列的正常行为,因此可以将具有高重建误差的数据点定义为异常。要记住的主要思想是频繁的事件很容易重建,但不频繁的事件却没有那么简单。因此,后者的重构误差会更高。

周期性神经网络中——包括LSTM——是专门设计用于连续数据的工作。他们非常擅长记住过去的数据,并且由于这一重要特征,可以完成更好的预测。如果你想完全理解它们是如何工作的,我建议你看看François Chollet的“Deep Learning with Python”。

不幸的是,LSTM 网络不足以实现我们的目标,因此我们需要在我们的架构中添加一个自动编码器。让我们来看看基本的自动编码器架构:

自编码器是一种人工神经网络,用于以无监督的方式生成有效的数据编码。通过这样做,自编码器可以学习数据收集中最重要的特征。在我们的例子中,我们将使用它的重建能力来确定什么是异常,什么不是。如果它难以重建某些观察结果,我们可以推断这些是异常现象。

顺便说一下,我将使用重建损失作为衡量数据点重建错误程度的一种手段。什么,你会看到未来是与一些帮助的LSTM自动编码器的创建Keras

#Defining important parameters for the model creation
tsteps = X_train.shape[1]
nfeatures = X_train.shape[2]
 
detector = Sequential()
detector.add(layers.LSTM(128, input_shape=(tsteps, nfeatures),dropout=0.2))
detector.add(layers.Dropout(rate=0.5))
detector.add(layers.RepeatVector(tsteps))
detector.add(layers.LSTM(128, return_sequences=True,dropout=0.2))
detector.add(layers.Dropout(rate=0.5))
detector.add(layers.TimeDistributed(layers.Dense(nfeatures)))
 
detector.compile(loss='mae', optimizer='adam')

现在,让我们在训练集上拟合模型:

checkpoint = ModelCheckpoint("/kaggle/working/detector.hdf5", monitor='val_loss', verbose=1,save_best_only=True, mode='auto', period=1)
history1 = detector.fit(X_train,y_train,epochs=50,batch_size=128,verbose=1,validation_split=0.1,callbacks=[checkpoint],shuffle=False)

到目前为止,除了ModelCheckpoint实现之外,没什么特别的。它保存了训练过程中获得的最佳模型。在过程结束时,这是我得到的(请记住,您的结果可能与这些略有不同,因为每个AI训练周期都包含随机性元素):

Epoch 50/50
157/157 [==============================] - ETA: 0s - loss: 0.0268
Epoch 00050: val_loss did not improve from 0.11903
157/157 [==============================] - 1s 7ms/step - loss: 0.0268 - val_loss: 0.1922

要加载获得的最佳模型并对其进行评估,请发出以下命令:

detector = load_model("detector.hdf5")
detector.evaluate(X_test, y_test)

结果,我得到了:

174/174 [==============================] - 0s 3ms/step - loss: 0.0579

这一点也不坏。现在是设置静态阈值的时候了,这是定义数据点是否为异常的最简单方法。在我们的例子中,任何高于此阈值的错误都将被视为异常值。我们将获得训练集和测试集的MAE损失,并直观地确定适当的阈值:

X_train_pred = detector.predict(X_train)
loss_mae = np.mean(np.abs(X_train_pred - X_train), axis=1) #This is the formula to calculate MAE
sns.distplot(loss_mae, bins=100, kde=True)

X_test_pred = detector.predict(X_test)
loss_mae = np.mean(np.abs(X_test_pred - X_test), axis=1)
sns.distplot(loss_mae, bins=100, kde=True)

正如您在上面的图表中所看到的,高于0.150的观测值变得异常,但在其他一些场景中,此任务并不那么简单。出于这个原因,通常最好使用统计数据来更精确地识别此值。让我们将该数字设置为阈值并确定高于它的值,以便我们可以绘制异常情况:

threshold = 0.15
 
test_df = pd.DataFrame(test[tsteps:])
test_df['loss'] = loss_mae
test_df['threshold'] = threshold
test_df['anomaly'] = test_df.loss > test_df.threshold
test_df['Weighted_Price'] = test[tsteps:].Weighted_Price
 
anomalies = test_df[test_df.anomaly == True]
yvals1 = scaler.inverse_transform(test[tsteps:][['Weighted_Price']])
yvals1 = yvals1.reshape(-1)
yvals2 = scaler.inverse_transform(anomalies[['Weighted_Price']])
yvals2 = yvals2.reshape(-1)
 
fig = go.Figure()
fig.add_trace(go.Scatter(x=test[tsteps:].index, y=yvals1,mode='lines',name='BTC Price'))
fig.add_trace(go.Scatter(x=anomalies.index, y=yvals2,mode='markers',name='Anomaly'))
fig.update_layout(showlegend=True,title="BTC price anomalies",xaxis_title="Time",yaxis_title="Prices",font=dict(family="Courier New, monospace"))
fig.show()

此图显示了测试集中的异常情况:

异常看起来很有希望。让我们看一下整个数据集并在其上绘制现有的异常:

scaled_pano = test.append(train, ignore_index=False)
X_shifted, y_shifted = shift_samples(scaled_pano[['Weighted_Price']], scaled_pano.columns[0])
X_shifted_pred = detector.predict(X_shifted)
loss_mae = np.mean(np.abs(X_shifted_pred - X_shifted), axis=1)
non_scaled_pano = pano.copy()[51000:]
non_scaled_pano.fillna(method ='bfill', inplace = True)
non_scaled_pano = non_scaled_pano[:-24]
non_scaled_pano['loss_mae'] = loss_mae
non_scaled_pano['threshold'] = threshold
non_scaled_pano['anomaly'] = non_scaled_pano.loss_mae > non_scaled_pano.threshold
pano_outliers = non_scaled_pano[non_scaled_pano['anomaly'] == True]
 
fig = go.Figure()
fig.add_trace(go.Scatter(x=non_scaled_pano.index, y=non_scaled_pano['Weighted_Price'].values,mode='lines',name='BTC Price'))
fig.add_trace(go.Scatter(x=pano_outliers.index, y=pano_outliers['Weighted_Price'].values,mode='markers',name='Anomaly'))
fig.update_layout(showlegend=True,title="BTC price anomalies - Autoencoder",xaxis_title="Time",yaxis_title="Prices",font=dict(family="Courier New, monospace"))
fig.show()

正如你所看到的,因为突出的价格是非常罕见的图表中,其结果符合我们的预期比特币的整个历史价格(见Bitcoin的历史价格请点击这里)。我们将保留此模型作为本系列其余部分的异常检测器。

下一步

接下来的文章中,我们打算在Bitcoin的时间序列预测讨论。敬请关注!

https://www.codeproject.com/Articles/5295163/AI-Anomaly-Detection-on-Bitcoin-Time-Series-Data

标签:loss,比特,AI,pano,scaled,test,序列,detector,异常
来源: https://blog.csdn.net/mzl87/article/details/118254862

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有