如何爲LSTMs準備數據

內容來源:
Jason Brownlee《 long-short-term-memory-networks-with-python》chapter 3
本文爲個人學習記錄,原書爲英文,使用copytranslator進行翻譯,個別地方進行手動校正,如有不易理解的地方還望讀者諒解,謝謝!

3.1 準備數值數據

訓練神經網絡(如長-短期記憶遞歸神經網絡)時,可能需要縮放序列預測問題的數據。當網絡適合具有一系列值(例如10到100秒的數量)的無標度數據時,大的輸入可能會減慢網絡的學習和收斂速度,並且在某些情況下會阻止網絡客觀地學習您的問題。

您可能需要考慮兩種類型的系列縮放:標準化和標準化。這兩個都可以通過使用Python中的scikit learn機器學習庫來實現。

3.1.1 歸一化系列數據(Normalize Series Data)

歸一化是對原始範圍內的數據進行重新縮放,使所有值都在0和1的範圍內。歸一化要求您知道或能夠準確估計最小和最大可觀測值。您可以根據可用的數據估計這些值。如果序列呈上升或下降趨勢,估計這些期望值可能會很困難,並且歸一化可能不是解決問題的最佳方法。

如果要縮放的值超出最小值和最大值的範圍,則結果值將不在0和1的範圍內。您可以在進行預測之前檢查這些觀測值,並將其從數據集中刪除,或將其限制爲預定義的最大值或最小值。可以使用scikit學習對象MinMaxScaler規範化數據集。使用MinMaxScaler和其他縮放技術的良好實踐如下:使用可用的訓練數據調整縮放器。對於歸一化,這意味着訓練數據將用於估計最小和最大可觀測值。這是通過調用fit()函數來完成的。

將量表應用於培訓數據。這意味着您可以使用規範化數據來訓練模型。這是通過調用transform()函數來完成的。

將比例應用於未來的數據。這意味着您可以在將來準備新的數據,以便進行預測。

如果需要,可以反轉變換。這對於將預測轉換回其原始比例以進行報告或繪製非常有用。這可以通過調用inverse transform()函數來完成。下面是一個將10個量的僞序列正規化的示例。scaler對象要求以行和列的矩陣形式提供數據。加載的時間序列數據作爲Pandas序列加載。

from pandas import Series
from sklearn.preprocessing import MinMaxScaler
# define contrived series
data = [10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0]
series = Series(data)
print(series)
# prepare data for normalization
values = series.values
values = values.reshape((len(values), 1))
# train the normalization
scaler = MinMaxScaler(feature_range=(0, 1))
scaler = scaler.fit(values)
print('Min: %f, Max: %f' % (scaler.data_min_, scaler.data_max_))
# normalize the dataset and print
normalized = scaler.transform(values)
print(normalized)
# inverse transform and print
inversed = scaler.inverse_transform(normalized)
print(inversed)

運行示例將打印序列,打印從序列中估計的最小值和最大值,打印相同的規格化序列,然後使用逆變換將值打印回其原始比例。我們還可以看到,數據集的最小值和最大值分別爲10.0和100.0。

0 10.0
1 20.0
2 30.0
3 40.0
4 50.0
5 60.0
6 70.0
7 80.0
8 90.0
9 100.0

Min: 10.000000, Max: 100.000000

[[ 0. ]
[ 0.11111111]
[ 0.22222222]
[ 0.33333333]
[ 0.44444444]
[ 0.55555556]
[ 0.66666667]
[ 0.77777778]
[ 0.88888889]
[ 1. ]]

[[ 10.]
[ 20.]
[ 30.]
[ 40.]
[ 50.]
[ 60.]
[ 70.]
[ 80.]
[ 90.]
[ 100.]]

3.1.2 標準化系列數據(Standardize Series Data)

標準化數據集涉及重新調整值的分佈,使觀測值的平均值爲0,標準偏差爲1。這可以被認爲是減去平均值或使數據居中。

與歸一化一樣,標準化也是有用的,甚至在某些機器學習算法中,當數據具有具有不同比例的輸入值時,標準化也是必需的。標準化假設您的觀測值符合高斯分佈(bell曲線),具有良好的平均值和標準偏差。如果不滿足這一期望,您仍然可以將時間序列數據標準化,但可能無法獲得可靠的結果。

標準化要求你知道或能夠準確估計可觀測值的平均值和標準差。您可以根據培訓數據估計這些值。與最小值和最大值相比,數據集的平均值和標準差估計對新數據的魯棒性更強。您可以使用scikit學習對象 StandardScaler 對數據集進行標準化。

from pandas import Series
from sklearn.preprocessing import StandardScaler
from math import sqrt
# define contrived series
data = [1.0, 5.5, 9.0, 2.6, 8.8, 3.0, 4.1, 7.9, 6.3]
series = Series(data)
print(series)
# prepare data for normalization
values = series.values
values = values.reshape((len(values), 1))
# train the normalization
scaler = StandardScaler()
scaler = scaler.fit(values)
print( 'Mean: %f, StandardDeviation: %f' % (scaler.mean_, sqrt(scaler.var_)))
# normalize the dataset and print
standardized = scaler.transform(values)
print(standardized)
# inverse transform and print
inversed = scaler.inverse_transform(standardized)
print(inversed)

運行示例打印序列,打印序列估計的平均值和標準偏差,打印標準值,然後按原始比例打印值。我們可以看到,估計的平均值和標準差分別約爲5.3和2.7。

0    1.0
1    5.5
2    9.0
3    2.6
4    8.8
5    3.0
6    4.1
7    7.9
8    6.3
dtype: float64
Mean: 5.355556, StandardDeviation: 2.712568
[[-1.60569456]
 [ 0.05325007]
 [ 1.34354035]
 [-1.01584758]
 [ 1.26980948]
 [-0.86838584]
 [-0.46286604]
 [ 0.93802055]
 [ 0.34817357]]
[[1. ]
 [5.5]
 [9. ]
 [2.6]
 [8.8]
 [3. ]
 [4.1]
 [7.9]
 [6.3]]

3.1.3 縮放時的實際考慮

在縮放序列數據時有一些實際考慮。

估計係數。您可以從培訓數據中估計係數(標準化的最小值和最大值,標準化的平均值和標準偏差)。檢查這些第一次切割估計,並使用領域知識或領域專家幫助改進這些估計,以便它們在將來對所有數據都有用地進行更正。

保存係數。在將來,您將需要以與用於訓練模型的數據完全相同的方式縮放新數據。保存用於存檔的係數,並在以後進行預測時需要縮放新數據時加載它們。
數據分析。使用數據分析幫助您更好地理解數據。例如,一個簡單的直方圖可以幫助您快速瞭解數量的分佈,看看標準化是否有意義。

縮放每個系列。如果問題有多個序列,請將每個序列視爲單獨的變量,然後分別縮放它們。這裏,scale指的是縮放過程的選擇,例如標準化或標準化。

在正確的時間縮放。在正確的時間應用任何縮放變換都很重要。例如,如果您有一系列非平穩的量,則在第一次使數據平穩後縮放可能比較合適。將序列轉換爲監督學習問題後縮放該序列是不合適的,因爲每個列都會被不同地處理,這是不正確的。

如有疑問,請按比例縮放。您可能需要重新調整輸入和輸出變量的大小。如果有疑問,至少要規範化數據。

3.2 準備分類數據

分類數據是包含標籤值而不是數值的變量。可能值的數目通常限制在一個固定的集合內。分類變量通常被稱爲名詞變量。

一些例子包括:

  1. 一個pet變量,其值爲dog和cat。
  2. 一個顏色變量,其值爲:紅色、綠色和藍色。
  3. 具有以下值的place變量:first、second和third。

每個值代表不同的類別。文本中的單詞可被視爲分類數據,其中每個單詞被視爲不同的類別。此外,文本數據中的每個字母都可以被視爲一個類別。文本輸入或輸出的序列預測問題可以被認爲是分類數據。

有些類別之間可能有一種自然的關係,例如自然順序。上面的place變量確實具有值的自然順序。這種類型的分類變量稱爲序數變量。使用LSTMs時,分類數據必須轉換爲數字。

3.2.1如何將分類數據轉換爲數值數據

這涉及兩個步驟:

  1. Integer Encoding.
  2. One Hot Encoding.

Integer Encoding

作爲第一步,爲每個唯一的類別值分配一個整數值。例如,紅色是1,綠色是2,藍色是3。這稱爲標籤編碼或整數編碼,並且很容易可逆。對於某些變量,這可能就足夠了。

整數值之間具有自然的有序關係,機器學習算法可以理解和利用這種關係。例如,上面的place示例這樣的序數變量將是一個很好的示例,其中標籤編碼就足夠了。

One Hot Encoding

對於不存在這種順序關係的分類變量,整數編碼是不夠的。事實上,使用這種編碼並允許模型假定類別之間的自然順序可能會導致性能差或意外結果(類別之間的中間預測)。

在這種情況下,可以對整數表示應用One Hot Encoding。這是刪除整數編碼變量併爲每個唯一整數值添加新二進制變量的位置。在顏色變量示例中,有3個類別,因此需要3個二進制變量。顏色的二進制變量中放置1值,其他顏色的二進制變量中放置0值。例如:

red, green, blue
1, 	   0,    0
0, 	   1, 	 0
0, 	   0, 	 1

3.2.2 使用scikit learn對數據進行 one-hot 編碼

在本例中,我們假設您有以下3個標籤的輸出序列:cold、warm、Hot。10個時間步驟的示例序列可以是:

cold、cold、warm、cold、hot、hot、warm、cold、warm、hot

這首先需要整數編碼,例如1、2、3。接下來是對整數進行一次熱編碼,得到一個包含3個值的二進制向量,例如[1,0,0]。序列提供了序列中每個可能值的至少一個示例。因此,我們可以使用自動方法定義標籤到整數的映射和整數到二進制向量的映射。

在本例中,我們將使用scikit學習庫中的編碼器。具體地說,創建標籤的整數編碼的LabelEncoder和創建整數編碼值的one-hot encoding的onehotecoder。下面列出了完整的示例。

from numpy import array
from numpy import argmax
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder
# define example
data = ['cold', 'cold', 'warm', 'cold', 'hot', 'hot', 'warm', 'cold', 'warm', 'hot']
values = array(data)
print(values)
# integer encode
label_encoder = LabelEncoder()
integer_encoded = label_encoder.fit_transform(values)
print(integer_encoded)
# binary encode
onehot_encoder = OneHotEncoder(sparse=False)
integer_encoded = integer_encoded.reshape(len(integer_encoded), 1)
onehot_encoded = onehot_encoder.fit_transform(integer_encoded)
print(onehot_encoded)
# invert first example
inverted = label_encoder.inverse_transform([argmax(onehot_encoded[0, :])])
print(inverted)

運行示例首先打印標籤序列。接下來是標籤的整數編碼,最後是一個熱編碼。訓練數據包含所有可能的示例集,因此我們可以依賴整數和一個熱編碼轉換來創建標籤到編碼的完整映射。

默認情況下,onehotecoder類將返回更有效的稀疏編碼。這可能不適合深度學習lib庫等應用程序。在這種情況下,我們通過設置sparse=False參數來禁用sparse返回類型。如果我們在這個3值1熱編碼中接收到預測,我們可以很容易地將轉換反轉回原始標籤。

首先,我們可以使用argmax()NumPy函數來定位具有最大值的列的索引。然後可以將其輸入LabelEncoder,以計算返回到文本標籤的反變換。這將在示例的末尾演示,其中第一個熱編碼示例的逆變換返回到標籤值cold。同樣,請注意輸入的格式是爲了可讀性。

['cold' 'cold' 'warm' 'cold' 'hot' 'hot' 'warm' 'cold' 'warm' 'hot']
[0 0 2 0 1 1 2 0 2 1]
[[1. 0. 0.]
 [1. 0. 0.]
 [0. 0. 1.]
 [1. 0. 0.]
 [0. 1. 0.]
 [0. 1. 0.]
 [0. 0. 1.]
 [1. 0. 0.]
 [0. 0. 1.]
 [0. 1. 0.]]
['cold']

3.3準備不同長度的序列

深度學習庫假設數據的矢量化表示。在可變長度序列預測問題中,這要求對數據進行轉換,使每個序列具有相同的長度。這種矢量化允許代碼爲您選擇的深度學習算法高效地批量執行矩陣操作。

3.3.1 序列填充(Sequence Padding )

在Keras深度學習lib庫中,PAD序列()函數可以用來填充可變長度序列。默認的填充值是0.0,這適用於大多數應用程序,不過可以通過value參數指定首選值來更改。例如:要應用於序列開始或結束的填充,稱爲前序列或後序列填充,可以由padding參數指定,如下所示。

預序列填充(Pre-Sequence Padding)

Pre-Sequence Padding是默認值(Padding=‘Pre’)。下面的示例演示如何使用0值預添加3個輸入序列。

from keras.preprocessing.sequence import pad_sequences
# define sequences
sequences = [
    [1, 2, 3, 4],
    [1, 2, 3],
    [1]
    ]
# pad sequence
padded = pad_sequences(sequences)
print(padded)

運行該示例將打印用零值預填充的3個序列。

[[1 2 3 4]
 [0 1 2 3]
 [0 0 0 1]]

後置序列填充(Post-Sequence Padding)

填充也可以應用於序列的末尾,這可能更適合於某些問題域。可以通過將padding參數設置爲Post來指定Post序列填充。

from keras.preprocessing.sequence import pad_sequences
# define sequences
sequences = [
    [1, 2, 3, 4],
    [1, 2, 3],
    [1]
    ]
# pad sequence
padded = pad_sequences(sequences, padding='post')
print(padded)

運行示例將打印後置序列填充的相同序列

[[1 2 3 4]
 [1 2 3 0]
 [1 0 0 0]]

3.3.2序列截斷(Sequence Truncation)

序列的長度也可以修剪到所需的長度。序列所需的長度可以用maxlen參數指定爲多個時間步。有兩種方法可以截斷序列:從序列的開始或結束刪除時間步。

預序列截斷默認的截斷方法是從序列開始處刪除時間步。這稱爲預序列截斷。下面的示例將序列截斷爲所需的長度2。

from keras.preprocessing.sequence import pad_sequences
# define sequences
sequences = [
    [1, 2, 3, 4],
    [1, 2, 3],
    [1]
    ]

# truncate sequence
truncated= pad_sequences(sequences, maxlen=2)
print(truncated)

運行該示例將從第一個序列中刪除前兩個時間步驟,從第二個序列中刪除第一個時間步驟,並填充最後一個序列。

[[3 4]
 [2 3]
 [0 1]]

後序列截斷(Post-Sequence Truncation)

序列也可以通過刪除序列末尾的時間步長來進行修剪。這種方法可能更適合於一些問題領域。通過將截斷參數從默認pre更改爲Post,可以配置Post序列截斷,如下所示:

from keras.preprocessing.sequence import pad_sequences
# define sequences
sequences = [
    [1, 2, 3, 4],
    [1, 2, 3],
    [1]
    ]

# truncate sequence
truncated= pad_sequences(sequences, maxlen=2, truncating='post')
print(truncated)

運行該示例將從第一個序列中刪除最後兩個時間步驟,從第二個序列中刪除最後一個時間步驟,然後再次填充最後一個序列。

[[1 2]
 [1 2]
 [0 1]]

對於何時填充和何時截斷不同長度的輸入序列,沒有經驗法則。例如,爲了提高效率,在情感分析中截斷很長的文本可能是有意義的,或者填充短文本並讓模型學習忽略或顯式屏蔽零輸入值以確保沒有數據丟失也是有意義的。我建議爲序列預測問題測試一組不同的表示,並對那些產生最佳模型技巧的表示進行加倍。

3.4序列預測作爲監督學習

序列預測問題,必須重新構造爲監督學習問題。也就是說,數據必須從一個序列轉換爲一對輸入和輸出對。

3.4.1序列與監督學習

在我們開始之前,讓我們花點時間更好地理解原始輸入序列和監督學習數據的形式。考慮一個按時間索引排序的數字序列。
這可以看作是有序值的列表或列。例如:

0
1
2
3
4
5
6
7
8
9

有監督學習問題由輸入模式(X)和輸出模式(y)組成,因此算法可以學習如何從輸入模式預測輸出模式。
例如:

X, y
1, 2
2, 3
3, 4
4, 5
5, 6
6, 7
7, 8
8, 9

這將表示序列的1-滯後變換,使得必須在給定序列的前一時間步的情況下預測當前時間步。

3.4.2 Pandas shift()函數

幫助將時間序列數據轉換爲監督學習問題的關鍵函數是Pandas shift()函數。給定一個數據幀,shift()函數可用於創建向前推(前面添加了一行NaN值)或向後拉(後面添加了一行NaN值)的列的副本。

這是以監督學習格式爲時間序列數據集創建滯後觀測列和預測觀測列所需的行爲。讓我們看看shift()函數的一些實際例子。我們可以將模擬時間序列數據集定義爲10個數字的序列,在這種情況下,數據幀中的單個列如下所示:

from pandas import DataFrame
# define the sequence
df = DataFrame()
df['t'] = [x for x in range(10)]
print(df)

運行此示例將打印包含每個觀測的行索引的時間序列數據。

  t
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9

我們可以通過在頂部插入一個新行,將所有觀測值一步一步地向下移動。
因爲新行沒有數據,所以我們可以使用NaN來表示沒有數據。shift函數可以爲我們這樣做,我們可以將這個移位列插入到原始序列的旁邊。

from pandas import DataFrame
# define the sequence
df = DataFrame()
df['t'] = [x for x in range(10)]
# shift forward
df['t-1'] = df['t'].shift(1)
print(df)

運行該示例會在數據集中顯示兩列。第一個是原始觀測和一個新的移位列。我們可以看到,將序列向前移動一個時間步會產生一個原始的有監督學習問題,儘管X和y的順序不對。忽略行標籤的列。由於NaN值的原因,第一行必須被丟棄。第二行在第二列(input或X)中顯示0.0的輸入值,在第一列(output或y)中顯示1的值。

  t t-1
0 0 NaN
1 1 0.0
2 2 1.0
3 3 2.0
4 4 3.0
5 5 4.0
6 6 5.0
7 7 6.0
8 8 7.0
9 9 8.0

我們可以看到,如果我們可以以2、3和更多的移位重複這個過程,我們可以創建長輸入序列(X),用於預測輸出值(y)。

移位運算符也可以接受負整數值。這樣可以通過在末尾插入新行來將觀察結果向上拉。下面是一個例子:

from pandas import DataFrame
# define the sequence
df = DataFrame()
df[ t ] = [x for x in range(10)]
# shift forward
df[ t-1 ] = df[ t ].shift(-1)
print(df)

運行該示例將顯示一個新列,最後一個值是NaN值。我們可以看到forecast列可以作爲輸入(X),第二列作爲輸出值(y)。即0的輸入值可用於預測1的輸出值。

  t t+1
0 0 1.0
1 1 2.0
2 2 3.0
3 3 4.0
4 4 5.0
5 5 6.0
6 6 7.0
7 7 8.0
8 8 9.0
9 9 NaN

從技術上講,在時間序列預測術語中,當前時間(t)和未來時間(t+1,t+n)是預測時間,過去的觀測(t-1,t-n)用來進行預測。我們可以看到如何使用正移位和負移位從一個有監督學習問題的輸入和輸出模式序列的時間序列中創建新的數據幀。

這不僅允許經典的X->y預測,而且允許輸入和輸出都可以是序列的X->y預測。此外,移位函數也適用於所謂的多元時間序列問題。也就是說,我們有多個觀測值(例如溫度和壓力),而不是一組時間序列的觀測值。時間序列中的所有變量都可以向前或向後移動,以創建多變量輸入和輸出序列。

3.5進一步閱讀

本節爲進一步閱讀提供了一些資源。

3.5.1 Numeric Scaling APIs

  1. MinMaxScaler API in scikit-learn.
    https://goo.gl/H3qHJU
  2. StandardScaler API in scikit-learn.
    https://goo.gl/cA4vQi
  3. Should I normalize/standardize/rescale the data? Neural Nets FAQ.
    ftp://ftp.sas.com/pub/neural/FAQ2.html#A_std

3.5.2 Categorical Encoding APIs

  1. LabelEncoder API in scikit-learn.
    https://goo.gl/Y2bn3T
  2. OneHotEncoder API in scikit-learn.
    https://goo.gl/ynDMHN
  3. NumPy argmax() API.
    https://docs.scipy.org/doc/numpy/reference/generated/numpy.argmax.html

3.5.3 Varied Length Sequence APIs

  1. pad sequences() API in Keras.
    https://keras.io/preprocessing/sequence/

3.5.4 Supervised Learning APIs

  1. shift() function API in Pandas.
    https://goo.gl/N3M3nG

3.6 Extensions

您想深入到LSTMs的數據準備工作中嗎?本節列出本課的一些具有挑戰性的擴展。

在段落中,總結何時標準化數值數據、何時標準化以及在有疑問時應採取的措施。

開發一個自動將ASCII文本作爲分類數據進行熱編碼的功能,以及另一個解碼編碼格式的功能。

列出可能受益於填充輸入序列的序列預測問題的3個示例和可能受益於截斷輸入序列的3個示例。

給出了一個具有多年逐時觀測的單變量時間序列預測問題,並給出了對上一課中截斷的BPTT的理解,描述了將序列轉化爲有監督學習問題的3種方法。

開發一個Python函數,將序列自動轉換爲一個有監督的學習問題,其中輸入和輸出時間步的數量可以指定爲參數。

3.7 Summary

在本課中,您發現瞭如何準備序列數據以使用LSTM遞歸神經網絡。具體來說,您學習了:

  1. 如何縮放數字數據以及如何轉換分類數據。
  2. 如何填充和截斷不同長度的輸入序列。
  3. 如何將輸入序列轉化爲有監督學習問題。

接下來,您將在Keras庫中發現LSTM模型的生命週期。

發佈了53 篇原創文章 · 獲贊 13 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章