[데이터분석] bitcoin analysis 비트 코인 시계열 데이터에 대한 AI 이상 탐지

세르지오 비라 혼다

 

2021 년 2 월 26 일CPOL

이 기사에서는 시계열 데이터에 대한 이상 탐지에 대해 설명합니다.

여기에서는 시계열 데이터에 대한 이상 탐지에 대해 자세히 살펴보고이 작업을 수행 할 수있는 모델을 구축하는 방법을 살펴 보겠습니다.

[다운로드] AnomalyDetection-main.zip

소개

이 일련의 기사는 AI를 사용하여 완전한 기능의 시계열 예측기 및 이상 탐지기 애플리케이션을 개발하는 데 필요한 단계를 안내합니다. 우리의 예측 자 / 탐지기는 특히 비트 코인으로 암호 화폐 데이터를 다룰 것 입니다. 그러나이 시리즈를 따라 가면 학습 한 개념과 접근 방식을 유사한 성격의 모든 데이터 유형에 적용 할 수 있습니다.

이 시리즈를 최대한 활용하려면 Python , Machine Learning 및 Keras 기술 이 있어야 합니다. 전체 프로젝트는 내 "GitHub 저장소 에서 사용할 수 있습니다. 여기 와 여기 에서 완전한 대화 형 노트북을 확인할 수도 있습니다 .

에서 이전 기사 , 당신은 기계 학습 (ML)과 깊은 학습 (DL) 모델에 공급되는 시계열 데이터를 준비하는 방법을 배웠습니다. 이 기사에서는 이러한 종류의 데이터에서 이상을 감지하는 방법을 설명합니다.

이상 징후 이해

이상이 무엇인지 궁금 할 수 있습니까? 어떻게 감지 할 수 있습니까? 아직 실행되지 않은 시나리오에서 이상을 감지하는 것이 실제로 가능합니까? 이상 현상 은 불규칙한 것을 가리키는 인기있는 용어입니다. 통계에서 이상 치는 데이터 수집에서 드물거나 예상치 못한 이벤트 인 이상 값 이라고도합니다 . 데이터 세트의 분포가 거의 정상이면 평균에서 표준 편차가 2 인 모든 데이터 포인트가 이상 징후가됩니다.

이상 현상의 개념을 설명하기 위해 자동차 엔진의 온도는 섭씨 90도 미만이어야합니다. 그렇지 않으면 과열되어 고장납니다. 엔진의 냉동 시스템은 온도를 안전한 범위로 유지합니다. 실패하면 정말 높은 온도 값을 알 수 있습니다. 수학적으로는 오랜 기간 동안 90 미만의 값을 가지게되며 엔진이 붕괴 될 때까지 값이 갑자기 최대 150까지 올라갑니다. 시각적으로 이것이 의미하는 바입니다.

섭씨 70 ~ 90도 사이의 데이터 포인트가 표시되지만 차트 끝에 갑자기 다른 값이 패턴을 깨뜨립니다 (강조 표시된 값). 이러한 후자의 관측은 이상치이므로 이상입니다. 위의 그래프는 이상을 설명하는 패턴을 보여줍니다.

AI 관점에서 이상 감지

이제 이상이 무엇인지 알았습니다. 어떻게 감지합니까? 이상 탐지는 데이터 수집에서 예상치 못한 항목이나 이벤트 (매우 드물게 발생하는 항목)를 식별하는 프로세스입니다. 이상 탐지는 두 가지 유형으로 제공됩니다. 하나는 단일 공간 (단일 변수)의 값 분포를 위해 예상치 못한 데이터 포인트를 식별하는 프로세스 인 일 변량 이상 탐지입니다. 다른 하나는 다변량 이상 탐지로, 이상 값은 최소 두 변수의 비정상 점수 조합입니다.

이 시리즈는 일 변량 이상 탐지에 초점을 맞출 것입니다. 그러나 동일한 접근 방식이 다 변수 컨텍스트에서 이상을 감지하도록 설계된 더 복잡한 모델의 기준으로 작동 할 수 있습니다.

K- 평균 클러스터링으로 이상 징후 감지

권장 데이터 세트를 이미 확인했다면 레이블이 전혀 지정되어 있지 않다는 것을 알았을 것입니다. 즉, 무엇이 이상인지 아닌지 아직 명확하지 않다는 것을 의미합니다. 이것은 실제 사례에서 처리해야하는 일반적인 시나리오입니다. 이상 감지 문제에 직면하면 소스에서 직접 데이터를 수집하고 특정 기술을 적용하여 이상을 발견해야합니다. 이것이 바로 비지도 학습의 도움으로 우리가 할 일입니다. 비지도 학습은 패턴을 발견하기 위해 모델이 라벨이없는 데이터에 대해 학습되는 ML 유형입니다. 이론적으로 데이터를 그룹화하기 위해 사람의 개입이 필요하지 않으므로 요구 사항 인 경우 이상을 식별 할 수 있습니다.

K- 평균 클러스터링은 오늘날 가장 단순한 것 중 하나 인 매우 간단하지만 얼마나 유용한 지 알게 될 것입니다. K-Means Clustering 은 유사한 데이터 포인트를 그룹화하고 육안으로는 분명하지 않은 기본 패턴을 찾는 알고리즘입니다. K – 중심 수 – 주어진 데이터 세트에서 식별해야하는 그룹 또는 클러스터 수를 정의합니다. 유사성이있는 데이터 포인트 모음으로서의 클러스터입니다. 중심은 수학적으로 클러스터의 중심입니다.

알고리즘은 모든 클러스터의 시작점 인 K 중심을 무작위로 선택하여 데이터 처리를 시작한 다음 반복적으로 계산을 수행하여 중심 위치를 최적화합니다. 군집이 식별되면 알고리즘은 모든 단일 데이터 포인트를 가장 가까운 군집에 할당하고 해당 레이블을 모든 관측치에 추가합니다.

기본적인 예를 들어이를 시각화 해 보겠습니다. 다음과 같은 X 개의 임의 값이 있다고 가정합니다.

두 개의 클러스터를 쉽게 식별 할 수 있습니다.

이것이 바로 K-Means Clustering 알고리즘이하는 일입니다. 이제이 알고리즘이 데이터 세트에서 어떻게 작동하는지 살펴 보겠습니다. 다음 명령을 실행하십시오.

# 모델에 전달할 데이터 준비 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 ()

결과 데이터 프레임의 처음 5 개 행을 얻게됩니다.

위의 표에서 "outlier"열에 0이있는 모든 행은 정상을 나타내고 해당 열에 1이있는 모든 행은 예외입니다. 모델이 이러한 값을 식별하는 방법을 확인하기 위해 전체 데이터 세트를 플로팅 해 보겠습니다.

a = outliers_k_means.loc [outliers_k_means [ ' outlier' ] == 1 ] # 이상치 무화과 = 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 가격 이상-KMeans" , xaxis_title = " 시간" , yaxis_title = " 가격" , font = dict (family = " Courier New, monospace" )) fig.show ()

위의 차트는 지난 몇 주 동안 가격이 변칙적 이었기 때문에 실제 비트 코인 가격 현실과 다소 잘 맞습니다. 알고리즘은 ~ $ 13,000 이상의 값을 하나의 클래스로 클러스터링하고이 임계 값 미만의 값을 다른 클래스로 클러스터링합니다.

비트 코인 과거 가격에서 이상 징후를 감지하기위한 신경망 및 오토 인코더 구현

이제 Neural Networks (NN)의 도움을 받아 비지도 학습 기법을 사용해 봅시다 . 이 방법은 이상 감지에 훨씬 더 유연하고 정확한 것으로 알려져 있습니다.

오늘날 NN은 놀라운 힘과 훌륭한 결과로 인해 새로운 표준이되었습니다. 우리는 특별한 방법을 사용합니다 : 우리가 활용할 수 있습니다 LSTM (긴 단기 기억) 자율 학습 모델을 구축하기 위해 NN과 autoencoders을. 이 접근 방식의 주요 목표는 마지막 모델에서 얻은 결과를 개선하는 것이며, 현재 데이터 세트의 분포를 모델링하여 그 구조에 대해 더 많이 배울 계획입니다.

일반적으로 이상 탐지 문제는 데이터 세트에 레이블이 지정되었는지 여부에 따라 분류 또는 회귀로 처리 할 수 ​​있습니다. 다음으로 할 일은 데이터 세트를 회귀 문제로 모델링하는 것입니다. 여기서 네트워크의 재구성 오류를 정량화 할 것입니다. 이는 본질적으로 데이터 세트에서 시퀀스의 정상적인 동작을 재구성 할 수있는 모델을 구축하여 재구성 오류가 높은 데이터 포인트를 이상으로 정의 할 수 있음을 의미합니다. 명심해야 할 주요 아이디어는 빈번한 이벤트는 재구성하기가 매우 쉽지만 드물게 발생하는 이벤트는 그렇게 간단하지 않다는 것입니다. 따라서 후자의 재구성 오류는 더 높아질 것입니다.

재발의 NN - LSTM 포함은 - 특별히 순차적 데이터에 사용할 수 있습니다. 그들은 과거 데이터를 기억하는 데 능숙하며 그 중요한 기능으로 인해 더 나은 예측을 수행합니다. 작동 방식을 완전히 이해하려면 François Chollet의 " Deep Learning with Python "을 살펴 보는 것이 좋습니다 .

안타깝게도 LSTM 네트워크로는 목표를 달성하기에 충분하지 않으므로 아키텍처에 자동 인코더 를 추가해야합니다 . 기본 오토 인코더 아키텍처를 살펴 보겠습니다.

오토 인코더는 감독되지 않는 방식으로 효율적인 데이터 인코딩을 생성하는 데 사용되는 인공 NN입니다. 이를 통해 오토 인코더는 데이터 수집의 가장 중요한 기능을 학습 할 수 있습니다. 우리의 경우 재구성 기능을 사용하여 비정상적인 항목과 그렇지 않은 항목을 결정합니다. 특정 관측치를 재구성하는 데 어려움을 겪는다면 이것이 이상 현상이라고 추론 할 수 있습니다.

그건 그렇고, 나는 데이터 포인트의 재구성이 얼마나 잘못된지를 측정하는 수단으로 재구성 손실을 사용할 것입니다. 당신이 다음 볼 것은의 도움과 LSTM의 autoencoder의 창조 Keras :

# 모델 생성을위한 중요한 매개 변수 정의 tsteps = X_train.shape [ 1 ] nfeatures = X_train.shape [ 2 ] 검출기 = 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 훈련주기에 무작위 요소가 포함되어 있으므로 결과가 약간 다를 수 있음을 명심하십시오).

신기원 50/50 157/157 [=============================]-ETA : 0 초-손실 : 0.0268 Epoch 00050 : val_loss가 0.11903에서 개선되지 않았습니다. 157/157 [=============================]-1 초 7ms / 단계-손실 : 0.0268-val_loss : 0.1922

얻은 최상의 모델을로드하고 평가하려면 다음 명령을 실행하십시오.

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

결과적으로 다음을 얻었습니다.

174/174 [=============================]-0 초 3ms / 단계-손실 : 0.0579

이것은 전혀 나쁘지 않습니다. 이제 데이터 포인트가 이상인지 여부를 정의하는 가장 간단한 방법 인 정적 임계 값을 설정할 때입니다. 이 경우이 임계 값보다 높은 오류는 이상 값으로 간주됩니다. 훈련 및 테스트 세트에 대한 MAE 손실을 얻고 적절한 임계 값이 무엇인지 시각적으로 결정할 것입니다.

X_train_pred = detector.predict (X_train) loss_mae = np.mean (np.abs (X_train_pred-X_train), axis = 1) # 이것은 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), 축 = 1) sns.distplot (loss_mae, bins = 100, kde = True)

위의 차트에서 볼 수 있듯이 0.150보다 높은 관측치는 비정상적이지만 다른 시나리오에서는이 작업이 그렇게 간단하지 않습니다. 따라서 통계를 사용하여이 값을보다 정확하게 식별하는 것이 가장 좋습니다. 이 숫자를 임계 값으로 설정하고 그 위에있는 값을 결정하여 이상을 그릴 수 있습니다.

임계 값 = 0 . 15 test_df = pd.DataFrame (test [tsteps :]) test_df [ ' 손실' ] = loss_mae test_df [ ' threshold' ] = 임계 값 test_df [ ' anomaly' ] = test_df.loss> test_df.threshold test_df [ ' Weighted_Price' ] = test [tsteps :]. Weighted_Price 이상 항목 = 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 ) 무화과 = 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 가격 이상" , xaxis_title = " 시간" , yaxis_title = " 가격" , 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), 축 = 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' ] = 임계 값 non_scaled_pano [ ' anomaly' ] = non_scaled_pano.loss_mae> non_scaled_pano.threshold pano_outliers = non_scaled_pano [non_scaled_pano [ ' anomaly' ] == True ] 무화과 = 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 가격 이상-Autoencoder" , xaxis_title = " 시간" , yaxis_title = " 가격" , font = dict (family = " Courier New, monospace" )) fig.show ()

당신이 볼 수있는 강조 표시된 가격은 차트에 매우 희귀하고 있기 때문에, 그 결과는 우리의 기대와 일치 또한 비트 코인의 전체 가격의 역사 (확인하십시오 비트 코인 역사 가격을보고 여기에 ). 이 시리즈의 나머지 부분에서는이 모델을 이상 탐지기로 유지합니다.

다음 단계

다음 기사에서는 비트 코인 시계열에 대한 예측에 대해 논의 할 것입니다. 계속 지켜봐주세요!

 

특허

이 기사는 관련 소스 코드 및 파일과 함께 The Code Project Open License (CPOL)에 따라 사용이 허가되었습니다 .

저자에 대하여

세르지오 비라 혼다

 

 

 
미국 

Sergio Virahonda는 베네수엘라에서 자랐으며 통신 공학 학사 학위를 받았습니다. 그는 4 년 전 해외로 이주했으며 그 이후로 의미있는 데이터 과학 경력을 쌓는 데 주력해 왔습니다. 그는 현재 아르헨티나에서 프리랜서 개발자로 코드를 작성하고 있습니다.

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

 

 

 

AI Anomaly Detection on Bitcoin Time Series Data

Sergio Virahonda

 

26 Feb 2021CPOL

In this article we talk about anomaly detection on time series data.

Here we’ll go deeper into anomaly detection on time-series data and see how to build models that can perform this task.

Introduction

This series of articles will guide you through the steps necessary to develop a fully functional time series forecaster and anomaly detector application with AI. Our forecaster/detector will deal with the cryptocurrency data, specifically with Bitcoin. However, after following along with this series, you’ll be able to apply the concepts and approaches you’ve learned to any data type of similar nature.

To fully benefit from this series, you should have some Python, Machine Learning, and Keras skills. The entire project is available in my "GitHub repository. You can also check out the fully interactive notebooks here and here.

In the previous article, you learned how to prepare time series data to be fed to machine learning (ML) and deep learning (DL) models. In this article, I’ll explain how to detect anomalies in this kind of data.

Understanding Anomalies

You might be wondering what is an anomaly? How could you detect it? Is it actually possible to detect anomalies in scenarios that haven’t played out yet? Anomaly is a popular term that refers to something irregular. In statistics, anomalies are often referred to as outliers – infrequent or unexpected events in a data collection. If the distribution of the dataset is approximately normal then anomalies would be all those data points that are 2 standard deviations from the mean.

To illustrate the concept of anomaly: a car engine’s temperature must be below 90 Centigrade, otherwise it will overheat and break down. The engine’s refrigeration system keeps the temperature in the safe range; if it fails, you could notice really high temperature values. Mathematically, you’d have values under 90 for a long period of time, then the values suddenly peak to150 until your engine collapses. Visually, this is what I mean:

You’d see data points between 70 and 90 Centigrade, but suddenly different values at the end of the chart break the pattern (the ones highlighted). These latter observations are outliers and, therefore, anomalies. The above graph shows a pattern that describes an anomaly.

Anomaly Detection from the AI Perspective

Now you know what an anomaly is - how do you detect it? As you may infer anomaly detection is the process of identifying the unexpected items or events in a data collection – those that occur very rarely. Anomaly detection comes in two flavors. One is the univariate anomaly detection which is the process of identifying those unexpected data points for a distribution of values in a single space (single variable). The other one is the multivariate anomaly detection, where an outlier is a combination of unusual scores of at least two variables.

I’ll focus these series on univariate anomaly detection. However, please note that the same approach can work as a baseline for more complex models, designed to detect anomalies in multivariate contexts.

Detecting Anomalies with K-Means Clustering

If you’ve checked the recommended datasets already, you’d have noticed that they aren’t labeled at all, meaning that it’s not yet clear what’s an anomaly and what’s not. This is the typical scenario you’ll have to deal with in real-world cases. When you face an anomaly detection challenge, you’ll have to gather the data coming directly from the source and apply certain techniques to discover anomalies. This is exactly what we’re going to do with some help from unsupervised learning. Unsupervised learning is a type of ML where the model is trained on unlabeled data in order to discover patterns. In theory, it doesn’t require human intervention to group the data and, therefore, identify anomalies — if that’s the requirement.

Keep in mind that K- Means Clustering is extremely simple – one of the simplest ones nowadays – but you’ll see how useful it can be. K-Means Clustering is an algorithm that groups similar data points and finds out underlying patterns that are not obvious to a naked eye. – the number of centroids –defines how many groups or clusters must be identified in a given dataset. A cluster as a collection of data points with similarities. A centroid is, mathematically, the center of a cluster.

The algorithm starts the data processing by randomly selecting K centroids, which are the starting points for every cluster, and then iteratively makes calculations to optimize the centroid positions. Once the clusters have been identified, the algorithm allocates every single data point to the closest cluster, and adds the corresponding label to every observation.

Let’s visualize this with a basic example. TSuppose that you have X random values that plot like this:

You can easily identify two clusters:

And that’s what the K-Means Clustering algorithm does, in a nutshell. Now let’s see how this algorithm works on our dataset. Issue the next commands:

# 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()

You’ll get the first five rows of the resulting dataframe:

In the above table, every row with 0 in the "outlier" column indicates a normal, and every one with 1 in that column - an anomaly. Let’s plot the entire dataset to see how the model identifies these values:

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()

The above chart fits rather well with the actual Bitcoin price reality because the last few weeks the price has been an anomaly. The algorithm clusters values above ~$13,000 as one class, and the values below this threshold – as another one.

Implementing Neural Networks and Autoencoders to Detect Anomalies on Bitcoin historical Price

Now let’s use an unsupervised learning technique with some help from Neural Networks (NN). This way is known to be much more flexible and accurate for anomaly detection.

Nowadays, NNs are the new norm because of their amazing power and great results. We’ll use them in an unusual way: we’ll utilize an LSTM (long short-term memory) NN and autoencoders to build an unsupervised learning model. The main goal of this approach is to improve the results obtained with the last model, and I plan to do so by modeling the distribution of our current dataset so as to learn more about its structure.

Generally speaking, anomaly detection problems can be addressed as classification or regression, depending on whether the dataset is labeled. What we’re going to do next is to model our dataset as a regression problem, where we’re going to quantify the reconstruction error of our network. This essentially means that we’re going to build a model that can reconstruct the normal behavior of the sequences in our dataset so a data point that has a high reconstruction error can be defined as an anomaly. The main idea to keep in mind is that frequent events are quite easy to reconstruct but the infrequent ones are not that simple. Therefore, the reconstruction error for the latter will be higher.

The Recurrent NNs – including LSTM – are specially designed to work with sequential data. They are great at remembering past data and, due to that important feature, accomplish better predictions. If you want to fully understand how they work, I recommend that you have a look at "Deep Learning with Python" by François Chollet.

Unfortunately, the LSTM network is not enough to achieve our goal, so we’ll need to add an autoencoder to our architecture. Let’s take a look at the basic autoencoder architecture:

An autoencoder is an artificial NN used to produce efficient data encodings in an unsupervised way. By doing this, the autoencoder can learn the most important features of the data collection. In our case, we’ll use its reconstruction capabilities to determine what’s an anomaly and what’s not. If it struggles with reconstructing certain observations, we can infer that these are anomalies.

By the way, I’m going to use the reconstruction loss as a means to measure how wrong a data point’s reconstruction is. What you’ll see next is the creation of an LSTM autoencoder with some help from 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')

Now, let’s fit the model on the training set:

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)

Nothing fancy so far except the ModelCheckpoint implementation. It saves the best model obtained during training. At the end of the process, this is what I’ve obtained (keep in mind that your results may vary slightly from these since every AI training cycle contains an element of randomness):

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

To load the best model obtained and evaluate it, issue these commands:

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

As a result, I’ve obtained:

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

This is not bad at all. Now it’s time to set a static threshold, which is the simplest way to define whether or not a data point is an anomaly. In our case, any error higher than this threshold will be considered an outlier. We’re going to get the MAE loss for the training and test sets and visually determine what would be the appropriate threshold:

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)

As you can see in the above charts, observations higher than 0.150 become unusual but in some other scenarios this task is not as simple. For that reason, it's often best to use statistics to identify this value with more precision. Let's set that number as the threshold and determine what value is above it, so that we can plot the anomalies:

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()

This plot shows the anomalies in the test set:

The anomalies look promising. Let’s take a look at the entire dataset and plot the existing anomalies on it:

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()

And as you can see, the results match our expectations because the highlighted prices are very rare in the chart and also Bitcoin's entire price history (to see the Bitcoin historical price please check here). We'll keep this model as our anomaly detector for the rest of this series.

Next Step

In the next article, we are going to discuss forecasting on Bitcoin time series. Stay tuned!

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Sergio Virahonda

 

 

 
United States 

Sergio Virahonda grew up in Venezuela where obtained a bachelor's degree in Telecommunications Engineering. He moved abroad 4 years ago and since then has been focused on building meaningful data science career. He's currently living in Argentina writing code as a freelance developer.

 

 

 

 

 

 

 

 

 

+ Recent posts