LSTM keras多功能:我做错了什么



下面的代码通过3个输入预测Close值(股价(:CloseOpenVolume。数据集:

Close    Open   Volume
Date                               
2019-09-20  5489.0  5389.0  1578781
2019-09-23  5420.0  5460.0   622325
2019-09-24  5337.5  5424.0   688395
2019-09-25  5343.5  5326.5   628849
2019-09-26  5387.5  5345.0   619344
...            ...     ...      ...
2020-03-30  4459.0  4355.0  1725236
2020-03-31  4715.0  4550.0  2433310
2020-04-01  4674.5  4596.0  1919728
2020-04-02  5050.0  4865.0  3860103
2020-04-03  5204.5  5050.0  3133078
[134 rows x 3 columns]

信息:

<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 134 entries, 2019-09-20 to 2020-04-03
Data columns (total 3 columns):
#   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
0   Close   134 non-null    float64
1   Open    134 non-null    float64
2   Volume  134 non-null    int64  
dtypes: float64(2), int64(1)

问题是如何纠正脚本,以获得正确的预测与3个功能过去10天,因为我得到了这个:

Epoch 1/1
64/64 [==============================] - 6s 88ms/step - loss: 37135470.9219
[[32.588608]
[32.587284]
[32.586754]
[32.587196]
[32.58649 ]
[32.58663 ]
[32.586098]
[32.58682 ]
[32.586452]
[32.588108]]
rmse: 4625.457010985681

即使我完全取消缩放(fit_transform(,问题仍然存在。在其他主题中,我被告知没有必要缩放y_train。完整的脚本代码:

from math import sqrt
from numpy import concatenate
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import mean_squared_error
from keras.models import Sequential
from keras.layers import Dense, Dropout, Embedding
from keras.layers import LSTM
import numpy as np
from datetime import datetime, timedelta
import yfinance as yf
start = (datetime.now() - timedelta(days=200)).strftime("%Y-%m-%d")
end = (datetime.now() - timedelta(days=1)).strftime("%Y-%m-%d")
df = yf.download(tickers="LKOH.ME", start=start, end=end, interval="1d")
dataset = df.loc[start:end].filter(['Close', 'Open', 'Volume']).values
scaler = MinMaxScaler(feature_range=(0,1))
training_data_len = len(dataset) - 10 # last 10 days to test
train_data = dataset[0:int(training_data_len), :]
x_train = []
y_train = []
for i in range(60, len(train_data)):
x_train.append(train_data[i-60:i, :]) # get all 3 features
y_train.append(train_data[i, 0]) # 0 means we predict Close
x_train, y_train = np.array(x_train), np.array(y_train)
x_train = x_train.reshape((x_train.shape[0], x_train.shape[1]*x_train.shape[2])) # convert to 2d for fit_transform()
x_train = scaler.fit_transform(x_train)
x_train = np.reshape(x_train, (x_train.shape[0], x_train.shape[1], 1))
model = Sequential()
# Do I need to change it to input_shape=(x_train.shape[1], 3), because of 3 features?
model.add(LSTM(50, return_sequences=True, input_shape=(x_train.shape[1], 1)))
model.add(LSTM(50))
model.add(Dense(25))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mean_squared_error')
model.fit(x_train, y_train, batch_size=1, epochs=1)
test_data = dataset[training_data_len - 60:, :]
x_test = []
y_test = dataset[training_data_len:, 0]
for i in range(60, len(test_data)):
x_test.append(test_data[i-60:i, :])
x_test = np.array(x_test)
x_test = x_test.reshape((x_test.shape[0], x_test.shape[1]*x_test.shape[2]))
x_test = scaler.fit_transform(x_test)
x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1], 1))
predictions = model.predict(x_test)
print(predictions)
print('rmse:', np.sqrt(np.mean(((predictions - y_test) ** 2))))

尽管公布的答案在技术上是正确的,并提供了有用的参考,但我发现拟合的结果没有多大意义,这有点烦人(你可以注意到预测是恒定的,即使y_test不是(。是的,缩放修复了损失——L2度量的值在1000左右,这使得任何基于梯度的算法都非常不稳定,而Rishab的答案解决了这一问题。这是我的代码片段。除了缩放之外,还有以下变化:

  • 使用更多数据。我随机选择了10000天,但如果有更多,你可能会得到更好的结果。200个点不足以获得比直线更好的收敛性
  • 随着点数的增加,使用更大的批次,否则需要一段时间才能适应
  • 对于较大的批次,使用更多的历元(尽管在这种情况下,超过3个并不能产生更好的收敛性(

最后,不要只看RMSE,绘制数据。较小的RMSE并不一定意味着有任何有意义的适合。

通过下面的片段,我对火车数据有了一个很好的拟合。预见问题:是的,我完全知道我对数据拟合过度,但这正是收敛至少应该做的,因为拟合一条直线对这类问题的意义要小得多。至少,这是在假装预测什么。

from math import sqrt
from numpy import concatenate
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import mean_squared_error
from keras.models import Sequential
from keras.layers import Dense, Dropout, Embedding
from keras.layers import LSTM
import numpy as np
from datetime import datetime, timedelta
import yfinance as yf
from matplotlib import pyplot as plt
start = (datetime.now() - timedelta(days=10000)).strftime("%Y-%m-%d")
end = (datetime.now() - timedelta(days=1)).strftime("%Y-%m-%d")
df = yf.download(tickers="LKOH.ME", start=start, end=end, interval="1d")
scaler = MinMaxScaler(feature_range=(0,1))
dataset = scaler.fit_transform(df.loc[start:end].filter(['Close', 'Open', 'Volume']).values)
training_data_len = len(dataset) - 10 # last 10 days to test
train_data = dataset[0:int(training_data_len), :]
x_train = []
y_train = []
for i in range(60, len(train_data)):
x_train.append(train_data[i-60:i, :]) # get all 3 features
y_train.append(train_data[i, 0]) # 0 means we predict Close
x_train, y_train = np.array(x_train), np.array(y_train)
x_train = x_train.reshape((x_train.shape[0], x_train.shape[1]*x_train.shape[2])) # convert to 2d for fit_transform()
x_train = np.reshape(x_train, (x_train.shape[0], x_train.shape[1], 1))
model = Sequential()
# Do I need to change it to input_shape=(x_train.shape[1], 3), because of 3 features?
model.add(LSTM(50, return_sequences=True, input_shape=(x_train.shape[1], 1)))
model.add(LSTM(50))
model.add(Dense(25))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mean_squared_error')
model.fit(x_train, y_train, batch_size=100, epochs=3)
test_data = dataset[training_data_len - 60:, :]
x_test = []
y_test = dataset[training_data_len:, 0]
for i in range(60, len(test_data)):
x_test.append(test_data[i-60:i, :])
x_test = np.array(x_test)
x_test = x_test.reshape((x_test.shape[0], x_test.shape[1]*x_test.shape[2]))
x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1], 1))
predictions = model.predict(x_test)
print(predictions)
print('rmse:', np.sqrt(np.mean(((predictions - y_test) ** 2))))

这是输出:

>>> print(predictions)
[[0.64643383]
[0.63276255]
[0.6288108 ]
[0.6320714 ]
[0.6572328 ]
[0.6998471 ]
[0.7333    ]
[0.7492812 ]
[0.7503019 ]
[0.75124526]]
>>> print('rmse:', np.sqrt(np.mean(((predictions - y_test) ** 2))))
rmse: 0.0712241892828221

绘图使用,用于训练数据拟合

plt.plot(model.predict(x_train))
plt.plot(y_train)
plt.show()    

以及测试预测

plt.plot(model.predict(x_test))
plt.plot(y_test)
plt.show()    

正如@rvinas已经提到的,我们需要缩放值,然后使用CCD_ 7以获得期望的预测结果。你可以在这里找到参考资料。

在对代码进行了一些小的更改之后,我能够得出令人满意的结果。我们可以使用data scaling方法和模型架构来改进结果。

经过一些增强

from math import sqrt
from numpy import concatenate
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import mean_squared_error
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Embedding
from tensorflow.keras.layers import LSTM
from tensorflow.keras.optimizers import SGD
import numpy as np
from datetime import datetime, timedelta
import yfinance as yf
start = (datetime.now() - timedelta(days=200)).strftime("%Y-%m-%d")
end = (datetime.now() - timedelta(days=1)).strftime("%Y-%m-%d")
df = yf.download(tickers="LKOH.ME", start=start, end=end, interval="1d")
dataset = df.loc[start:end].filter(['Close', 'Open', 'Volume']).values
scaler = MinMaxScaler(feature_range=(0,1))

dataset = scaler.fit_transform(dataset)
training_data_len = len(dataset) - 10 # last 10 days to test
train_data = dataset[0:int(training_data_len), :]
x_train = []
y_train = []
for i in range(60, len(train_data)):
x_train.append(train_data[i-60:i, :]) # get all 3 features
y_train.append(train_data[i, 0]) # 0 means we predict Close

x_train, y_train = np.array(x_train), np.array(y_train)
x_train = x_train.reshape((x_train.shape[0], x_train.shape[1]*x_train.shape[2])) # convert to 2d for fit_transform()
x_train_scale = scaler.fit(x_train)
x_train = np.reshape(x_train, (x_train.shape[0], x_train.shape[1], 1))
model = Sequential()
# Do I need to change it to input_shape=(x_train.shape[1], 3), because of 3 features?
# yes, i did that.
model.add(LSTM(units=50,return_sequences=True, kernel_initializer='random_uniform', input_shape=(x_train.shape[1], 1)))
model.add(Dropout(0.2))
model.add(LSTM(units=50,return_sequences=True, kernel_initializer='random_uniform'))
model.add(Dropout(0.2))
model.add(LSTM(units=50,return_sequences=True, kernel_initializer='random_uniform'))
model.add(Dropout(0.2))
model.add(LSTM(units=50, kernel_initializer='random_uniform'))
model.add(Dropout(0.2))
model.add(Dense(units=25, activation='relu'))
model.add(Dense(units=1))
# compile model
model.compile(optimizer='adam', loss='mean_squared_error')
model.summary()
model.fit(x_train, y_train, batch_size=5, epochs=2)
test_data = dataset[training_data_len - 60:, :]
x_test = []
y_test = dataset[training_data_len:, 0]
for i in range(60, len(test_data)):
x_test.append(test_data[i-60:i, :])
x_test = np.array(x_test)
x_test = x_test.reshape((x_test.shape[0], x_test.shape[1]*x_test.shape[2]))
x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1], 1))
predictions = model.predict(x_test)
# predictions = y_train_scale.inverse_transform(predictions)
print(predictions)
print('rmse:', np.sqrt(np.mean(((predictions - y_test) ** 2))))

预测1:

start = (datetime.now() - timedelta(days=200)).strftime("%Y-%m-%d")
opt = SGD(lr=0.01, momentum=0.9, clipnorm=1.0, clipvalue=0.5)
model.compile(loss='mean_squared_error', optimizer=opt)
[[0.6151125 ]
[0.6151124 ]
[0.6151121 ]
[0.6151119 ]
[0.61511195]
[0.61511236]
[0.61511326]
[0.615114  ]
[0.61511385]
[0.6151132 ]]
rmse: 0.24450220836260966

预测2:

start = (datetime.now() - timedelta(days=1000)).strftime("%Y-%m-%d")
model.compile(optimizer='adam', loss='mean_squared_error')
[[0.647125  ]
[0.6458076 ]
[0.6405072 ]
[0.63450944]
[0.6315386 ]
[0.6384401 ]
[0.65666   ]
[0.68073314]
[0.703547  ]
[0.72095114]]
rmse: 0.1236932687978488

股票市场价格是高度不可预测和波动的。这意味着数据中没有一致的模式可以让你对一段时间内的股价进行近乎完美的建模。所以这需要大量的R&D想出一个好的策略。

您可以做的事情:

  1. 将更多的训练数据添加到模型中,使其能够更好地进行泛化
  2. 使模型更深入。玩模型Hyperparameters来挤出模型的性能。你可以在这里找到一个关于超参数调整的好参考

您可以从以下参考链接中找到有关各种其他数据预处理技术和模型架构的更多信息:

Python 中LSTM的股票市场预测

机器学习预测股票价格

最新更新