手把手教你實戰時間序列分類模型(附python演練)

介紹

大多數的時間序列數據主要用於交易生成預測。無論是預測產品的需求量還是銷售量,航空公司的乘客數量還是特定股票的收盤價,我們都可以利用時間序列技術來預測需求。

手把手教你實戰時間序列分類模型(附python演練)

隨著生成的數據量呈指數級增長,嘗試新思想和算法的機會也隨之增加。使用複雜的時間序列數據集仍然是一個待開發的領域。

這篇文章的目的就是介紹時間序列分類的新概念。我們將首先了解該概念的含義和在行業中的應用。我們不會只停留在理論部分,還會通過處理時間序列數據集並執行分類解決實際問題。一邊做一邊學有助於以實際的操作來理解概念。

時間序列分類簡介

時間序列分類實際上已經存在了一段時間。但到目前為止,它主要用於實驗室研究,而不是行業應用。目前有很多正在進行的研究,新創建的數據集,許多新的算法。當我第一次接觸到到時間序列分類概念時,最初的想法是:我們怎樣對時間序列進行分類以及時間序列分類數據是什麼樣的?我相信你一定也想知道。

可以想象,時間序列分類數據與常規分類問題不同,因為它的屬性是有序序列。讓我們來看看一些時間序列分類用例,瞭解它們之間的差異。

1. ECG / EEG信號分類

心電圖(ECG, electrocardiogram),用於記錄心臟的電活動,並廣泛用於診斷各種心臟問題。使用外部電極捕獲這些ECG信號。

例如,考慮以下信號樣本,它代表一個心跳的電活動。左側圖像表示正常心跳,而相鄰的圖像表示心肌梗塞。

手把手教你實戰時間序列分類模型(附python演練)

從電極捕獲的數據將是時間序列的形式,並且信號可以分類為不同的類別。我們還可以對記錄大腦電活動的腦電信號進行分類。

2. 圖像分類

圖像也可以是時間順序相關的。考慮以下的情況:

根據天氣條件,土壤肥力,水的可用性和其他外部因素,作物在特定的田地中生長。在該區域上持續每天拍攝圖片,持續5年,並標記在該區域上種植作物的名稱。該數據集中的圖像是在固定的時間間隔拍攝的,並且具有特定的順序,這可能是對圖像進行分類的重要因素。

3. 運動傳感器數據分類

傳感器生成高頻數據,可以識別其範圍內物體的移動。通過設置多個無線傳感器並觀察傳感器中信號強度的變化,我們可以識別物體的運動方向。

你還知道哪些時間序列分類的應用嗎?歡迎大家在文末留言。

描述問題場景

我們將專注於 “室內用戶運動預測” 的問題。在該問題中,多個運動傳感器被放置在不同的房間中,目標是從這些運動傳感器捕獲的頻率數據中識別個體是否在房間之間移動。

兩個房間一共有四個運動傳感器(A1,A2,A3,A4)。請看下面的圖像,其中說明了傳感器在每個房間中的位置。一共設置了 3 對類似的房間(group1,group2,group3)。

手把手教你實戰時間序列分類模型(附python演練)

一個人可以沿著上圖所示的六個預定義路徑中的任意一個移動。路徑2, 3, 4或 6 是在房間內移動,路徑 1 或 5 在房間之間移動。

傳感器的讀數可以識別人在某個時間點的位置。當人在房間內或在房間內移動時,傳感器中的讀數會發生變化。改變化可用於標識人員的路徑。

現在問題已經表述清楚了,是時候開始編碼了!在下一節中,我們會查看該問題的數據集,有助於使該問題更加清晰。數據集:室內用戶移動預測。

查看數據集

數據集一共包含316個文件:

  • 314 個 MovementAAL csv 文件,包含環境中的運動傳感器的讀數。
  • 一個 Target csv 文件,包含每個 MovementAAL 文件的目標變量。
  • 一個 Group Data csv 文件,用於標識 MovementAAL 文件屬於哪一個組。
  • Path csv 文件包含目標採取的路徑。

首先看一下數據集。

import pandas as pd
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
from os import listdir

from keras.preprocessing import sequence
import tensorflow as tf
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from keras.optimizers import Adam
from keras.models import load_model
from keras.callbacks import ModelCheckpoint

在加載所有文件之前先快速瀏覽一下要處理的數據。讀取移動數據的前兩個文件:

df1 = pd.read_csv('/MovementAAL/dataset/MovementAAL_RSS_1.csv')
df2 = pd.read_csv('/MovementAAL/dataset/MovementAAL_RSS_2.csv')
d1.head()
手把手教你實戰時間序列分類模型(附python演練)

 df2.head()
手把手教你實戰時間序列分類模型(附python演練)

df1.shape, df2.shape

((27, 4), (26, 4))

這些文件包含了四個傳感器的標準化數據 —— A1,A2,A3,A4。csv 文件的長度(行數)不同,是因為對應的持續時間不同。為方便起見,我們假設每秒都會收集到傳感器數據。第一次變化持續時間為27秒(27行),而另一次變化為26秒(26行)。

在建立模型之前,我們必須處理這種不同的長度。以下的代碼用於讀取和存儲傳感器的值:

path = 'MovementAAL/dataset/MovementAAL_RSS_'
sequences = list()
for i in range(1,315):
file_path = path + str(i) + '.csv'
print(file_path)
df = pd.read_csv(file_path, header=0)
values = df.values
sequences.append(values)
targets = pd.read_csv('MovementAAL/dataset/MovementAAL_target.csv')
targets = targets.values[:,1]

現在有一個名為 'sequences' 的列表,包含了運動傳感器的數據和目標——csv文件的標籤。sequences[0] 中的數據就是第一個csv文件中獲取傳感器的值:

sequences[0]
手把手教你實戰時間序列分類模型(附python演練)

如上所述,數據集是在三對不同的房間中收集的,所以有三組數據。正好可以將數據集劃分為訓練集,測試集和驗證集。現在加載 DatasetGroup csv 文件:

groups = pd.read_csv('MovementAAL/groups/MovementAAL_DatasetGroup.csv', header=0)
groups = groups.values[:,1]

前兩組的數據用於訓練 ,第三組用於測試。

預處理

由於時間序列數據的長度不同,我們不能直接在數據集上建立模型。那麼怎樣確定合適的長度呢?我們可以通過多種方發處理。這裡有一些簡單的想法(歡迎在評論區提出批評和建議):

  • 用零填充較短的序列使所有序列的長度相等。這種方式下,我們向模型提供了不正確的數據
  • 找到序列的最大長度,使用它最後一行中的數據填充
  • 確定數據集中序列的最小長度,將其他所有的序列截斷為該長度。這將損失大量的數據
  • 取所有長度的平均值,截斷較長的序列,填充較短的序列

獲取最小,最大和平均序列長度:

len_sequences = []
for one_seq in sequences:
len_sequences.append(len(one_seq))
pd.Series(len_sequences).describe()
count 314.000000
mean 42.028662
std 16.185303
min 19.000000
25% 26.000000
50% 41.000000
75% 56.000000
max 129.000000
dtype: float64

大多數文件的長度在 40 到 60 之間。只有 3 個文件的長度超過 100。因此,採用最小或最大的長度沒有太大意義。第 90 個四分位數是 60,可以將它作為所有序列的長度。代碼:

# 用最長序列的最後一行的數據填充較短的序列
to_pad = 129
new_seq = []
for one_seq in sequences:
len_one_seq = len(one_seq)
last_val = one_seq[-1]
n = to_pad - len_one_seq

to_concat = np.repeat(one_seq[-1], n).reshape(4, n).transpose()
new_one_seq = np.concatenate([one_seq, to_concat])
new_seq.append(new_one_seq)
final_seq = np.stack(new_seq)

# 截斷較長的序列
from keras.preprocessing import sequence
seq_len = 60
final_seq=sequence.pad_sequences(final_seq, maxlen=seq_len, padding='post', dtype='float', truncating='post')

然後根據分組將數據集分開,準備訓練集,驗證集和測試集:

train = [final_seq[i] for i in range(len(groups)) if (groups[i]==2)]
validation = [final_seq[i] for i in range(len(groups)) if groups[i]==1]
test = [final_seq[i] for i in range(len(groups)) if groups[i]==3]

train_target = [targets[i] for i in range(len(groups)) if (groups[i]==2)]
validation_target = [targets[i] for i in range(len(groups)) if groups[i]==1]
test_target = [targets[i] for i in range(len(groups)) if groups[i]==3]
train = np.array(train)
validation = np.array(validation)
test = np.array(test)

train_target = np.array(train_target)
train_target = (train_target+1)/2

validation_target = np.array(validation_target)
validation_target = (validation_target+1)/2

test_target = np.array(test_target)
test_target = (test_target+1)/2

建立分類模型

我們已經準備了用於 LSTM(長短期記憶)模型的數據,處理了不同長度的序列並創建了訓練集,驗證集和測試集。接下來就要建立一個單層 LSTM 網絡。

model = Sequential()
model.add(LSTM(256, input_shape=(seq_len, 4)))
model.add(Dense(1, activation='sigmoid'))

model.summary()
手把手教你實戰時間序列分類模型(附python演練)

訓練模型並驗證準確率:

adam = Adam(lr=0.001)
chk = ModelCheckpoint('best_model.pkl', monitor='val_acc', save_best_only=True, mode='max', verbose=1)
model.compile(loss='binary_crossentropy', optimizer=adam, metrics=['accuracy'])
model.fit(train, train_target, epochs=200, batch_size=128, callbacks=[chk], validation_data=(validation,validation_target))

最後的準確度得分是0.78846153846153844。這是一個相當良好的開端,但我們還可以通過使用超參數,改變學習速率或迭代次數改善 LSTM 模型的性能。


分享到:


相關文章: