1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
| """
Обучал на ценах на акции за 4 года, за 5 год взял новый файл, и сеть
неправильно предсказала 15 день, цена открытия, тогда как обучалась
по окну - 14 дней назад и один вперед.
"""
import pandas as pd
from sklearn.preprocessing import StandardScaler
import numpy as np
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Dense, Dropout
import pickle
from matplotlib import pyplot as plt
import seaborn as sns
fpickle = 'learned.pkl'
def build_model_lstm(trainX, trainY):
model = Sequential()
model.add(
LSTM(64,
activation='relu',
input_shape=(trainX.shape[1], trainX.shape[2]),
return_sequences=True))
model.add(LSTM(32, activation='relu', return_sequences=False))
model.add(Dropout(0.2))
model.add(Dense(trainY.shape[1]))
model.compile(optimizer='adam', loss='mse')
model.summary()
return model
"""
Загружаем из pickle веса в модель(из функции build_model_lstm()) как обученную,
если указан параметр-имя файла fdump, если нет выдаем модель для compile/fit.
"""
def make_lstm(trainX, trainY, fdump=None):
model = build_model_lstm(trainX, trainY)
if fdump:
params = {}
with open(fdump, 'rb') as f:
params = pickle.load(f)
len_layers = len(model.layers)
for i in range(len_layers):
model.layers[i].set_weights(params[i])
return model
# для google colab
# from google.colab import drive
# drive.mount('/content/gdrive')
# fold_csv = '/content/gdrive/MyDrive/Colab Notebooks/data/GE.csv'
# /для google colab
# для компа
"""
c https://finance.yahoo.com/quote/GE/history/ - Генерал Электрик
4 года установил период торговли акциями, скачал
"""
fold_csv = './data/GE.csv'
"""
с того же, но год, за 2021.Для окончательного предсказания
"""
fold_csv_ask = './data/GE_ask.csv'
# /для компа
"""
Сохранить только веса модели в pickle файл.Это карта
key:int-номер слоя => value - значение матрицы весов.
"""
def save_model(model):
len_layers = len(model.layers)
weights = {}
for i in range(len_layers):
weights[i] = model.layers[i].get_weights()
with open(fpickle, 'wb') as f:
pickle.dump(weights, f)
print(f'saved learned to {fpickle}')
df = pd.read_csv(fold_csv) #df.shape -> (251, 7)
print(df.head()) #7 columns, including the Date.
"""
->
Date Open High Low Close Adj Close Volume
0 2016-01-04 235.000000 236.615387 232.692307 236.230774 213.058151 8174595
1 2016-01-05 236.000000 237.230774 234.230774 236.461533 213.266235 7172906
2 2016-01-06 232.846161 236.307693 231.153839 232.692307 209.866776 8144851
3 2016-01-07 228.076920 230.461533 221.923080 222.846161 200.986450 11994762
4 2016-01-08 224.615387 225.384613 218.000000 218.846161 197.378815 9684493
"""
train_dates = pd.to_datetime(df['Date'])
# type(train_dates[0]) -> <class 'pandas._libs.tslibs.timestamps.Timestamp'>
#Variables for training
cols = list(df)[1:6]
#Date and volume columns are not used in training.
print(cols) #['Open', 'High', 'Low', 'Close', 'Adj Close']
df_for_training = df[cols].astype(float) # len(df_for_training) -> 251
#LSTM uses sigmoid and tanh that are sensitive to magnitude so values need to be normalized
# normalize the dataset
scaler = StandardScaler()
scaler = scaler.fit(df_for_training)
df_for_training_scaled = scaler.transform(df_for_training)
"""
В дне 5 параметров биржи торгов (цена открытия, самая высокая, самая низкая, цена закрытия, приближенное к цене закрытия).
Фреймы составляют 14 таких дней (по 5 параметров), 1 параметр-цена открытия нас интересует на конце сети.Принцип окна по прошлому+1день(1
параметр) как цена открытия в будущем.
Чтобы обучить LSTM на наших данных, нам нужно преобразовать наши данные в форму, принятую LSTM.
Нам нужно преобразовать наши данные в трехмерный формат. Первое измерение-это количество записей или строк в наборе данных,
которое в нашем случае равно 251. Второе измерение-это количество временных шагов, равное 14,
а последнее измерение – количество индикаторов, 5.
Usman Malic делает так(одновариантная LSTM - раз индекс 0):
features_set = []
labels = []
for i in range(60, 1260):
features_set.append(apple_training_scaled[i-60:i, 0])
labels.append(apple_training_scaled[i, 0])
Говорит что на 60 днях назад бывают лучшее результаты(но у него и набор больше -1_260 рядов).
"""
def pass_window_throught_df():
#As required for LSTM networks, we require to reshape an input data into n_samples x timesteps x n_features.
#In this example, the n_features is 5. We will make timesteps = 14 (past days data used for training).
#Empty lists to be populated using formatted training data
trainX = []
trainY = []
n_future = 1 # Number of days we want to look into the future based on the past days.
n_past = 14 # Number of past days we want to use to predict the future.
#Reformat input data into a shape: (n_samples x timesteps x n_features)
#In my example, my df_for_training_scaled has a shape (12823, 5)
#12823 refers to the number of data points and 5 refers to the columns (multi-variables).
for i in range(n_past,
len(df_for_training_scaled) - n_future +
1): # len(df_for_training_scaled) -> 251
trainX.append(df_for_training_scaled[
i - n_past:i,
0:df_for_training.shape[1]]) # df_for_training.shape[1] -> 5
# акцентируется на 1-ом параметре(0-м)-цена открытия.Первый индекс - вертикально срезает окно(фрейм).
# 2-ой индекс горизонтально вытаскивает количество индикаторов с их позиций.
trainY.append(df_for_training_scaled[i + n_future - 1:i + n_future, 0])
trainX, trainY = np.array(trainX), np.array(trainY)
print('trainX shape == {}.'.format(
trainX.shape)) # trainX shape == (237, 14, 5).
print('trainY shape == {}.'.format(
trainY.shape)) # trainY shape == (237, 1).
return trainX, trainY
def learn():
trainX, trainY = pass_window_throught_df()
model = make_lstm(trainX, trainY)
model.compile(optimizer='adam', loss='mse', metrics=['accuracy'])
model.summary()
# fit the model
history = model.fit(trainX,
trainY,
epochs=5,
batch_size=16,
validation_split=0.20,
verbose=1)
plt.plot(history.history['loss'], label='Training loss')
plt.plot(history.history['val_loss'], label='Validation loss')
plt.legend()
plt.show()
save_model(model)
# learn()
df_test = pd.read_csv(fold_csv_ask) #df.shape -> (251, 7)
print(df_test.head()) #7 columns, including the Date.
#Variables for training
cols = list(df)[1:6]
#Date and volume columns are not used in training.
print(cols) #['Open', 'High', 'Low', 'Close', 'Adj Close']
df_for_testing = df[cols].astype(float) # len(df_for_training) -> 251
scaler_test = StandardScaler()
scaler_test_fitted = scaler_test.fit(df_for_testing)
scaler_test_fitted_trasformed=scaler_test.transform(df_for_testing)
my_mean=scaler_test.mean_
my_scale=scaler_test.scale_
np_for_testing_scaled = scaler.transform(df_for_testing)
trainX, trainY = pass_window_throught_df()
model = make_lstm(trainX, trainY)
n_days_past=14
X=np_for_testing_scaled[0 : n_days_past, : ]
prediction = model.predict(np.array([X]))
"""
Вообще чтобы вернуть из стандартизированного состояния, надо
X=X_startart_d * std + mean,
где X - восстановленные данные,
X_startart_d - ранее стандартизированные данные,
std - параметр отклонения после стандартизации,
mean - параметр среднее после стандартизации.
Но здесь для предсказанного воспользуемся средним.
"""
prediction=prediction[0][0] * np.mean(my_scale) + np.mean(my_mean)
print('answer open price', prediction) # answer open price -> 148.73902044297697
print('real open price', df_test.iloc[15][1] ) # real open price -> 96.239998
"""
Проверим разницу (в валюте насколько ошиблась сеть при предсказании на 15 день цены открытия по 14 дням прошлым (Январь))
"""
delta=prediction - df_test.iloc[15][1]
print('delta', delta) #delta -> 52.499022442976965 Это большая ошибка, хотя вроде сеть может показывать тренды. |