Lời mở đầu
Ở bài viết này, mình sẽ xây dựng mô hình hơn giản để áp dụng vào tập dữ liệu giá chứng khoáng. Mục tiêu của bài này là chúng ta sẽ dự đoán chỉ số S&P 500 sử dụng LSTM. Các bạn có nhu cầu tìm hiểu thêm về chỉ số sp 500 có thể đọc thêm ở https://vi.wikipedia.org/wiki/S%26P_500. Đây là một ứng dụng nhỏ, không có ý nghĩa nhiều ở thực tế do khi phân tích chứng khoán, ta còn xét thêm rất nhiều yếu tố phụ nữa. Mô hình này thực chất chỉ là một trong những mô hình chơi chơi.
Dẫn nhập
Phân tích dữ liệu
Các bạn có thể download dữ liệu ở https://github.com/AlexBlack2202/alexmodel/blob/master/GSPC.csv
Đầu tiên, như thường lệ, chúng ta sẽ import các thư viện cần thiết để sử dụng.
1import numpy as np # linear algebra
2import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
3
4from subprocess import check_output
5from keras.layers.core import Dense, Activation, Dropout
6from keras.layers.recurrent import LSTM
7from keras.models import Sequential
8from sklearn.cross_validation import train_test_split
9import time #helper libraries
10from sklearn.preprocessing import MinMaxScaler
11import matplotlib.pyplot as plt
12from numpy import newaxis
Đọc dữ liệu lên:
1
2file_name ='GSPC.csv'
3
4prices_dataset = pd.read_csv(file_name, header=0)
5
6``
7
8Xem kích thước của dữ liệu:
9
10```python
11print(prices_dataset.shape)
1(17114, 7)
Kết quả là ta có 17114 ngàn dòng và 7 cột. Thử show 10 row đầu tiên của dữ liệu lên xem như thế nào.
1print(prices_dataset.head())
1 Date Open High Low Close Adj Close Volume
20 1950-11-09 19.790001 19.790001 19.790001 19.790001 19.790001 1760000
31 1950-11-10 19.940001 19.940001 19.940001 19.940001 19.940001 1640000
42 1950-11-13 20.010000 20.010000 20.010000 20.010000 20.010000 1630000
53 1950-11-14 19.860001 19.860001 19.860001 19.860001 19.860001 1780000
64 1950-11-15 19.820000 19.820000 19.820000 19.820000 19.820000 1620000
Cột đầu tiên là ngày, sau đó là giá mở cửa, giá giao dịch cao nhất, giá giao dịch thấp nhât, giá đóng cử, giá đóng cửa đã điều chỉnh, khối lượng giao dịch.
Plot đồ thị của mã SP500 lên:
1import matplotlib.pyplot as plt
2
3plt.plot(prices_dataset.Open.values, color='red', label='open')
4plt.plot(prices_dataset.Close.values, color='green', label='close')
5plt.plot(prices_dataset.Low.values, color='blue', label='low')
6plt.plot(prices_dataset.High.values, color='black', label='high')
7plt.title('stock price')
8plt.xlabel('time [days]')
9plt.ylabel('price')
10plt.legend(loc='best')
11plt.show()
Hình với số lượng hơi nhiều nên khó phân biệt được giá trị của dữ liệu, chúng ta thử show đồ thị của 50 ngày cuối cùng trong dữ liệu.
1prices_dataset_tail_50 = prices_dataset.tail(50)
2
3plt.plot(prices_dataset_tail_50.Open.values, color='red', label='open')
4plt.plot(prices_dataset_tail_50.Close.values, color='green', label='close')
5plt.plot(prices_dataset_tail_50.Low.values, color='blue', label='low')
6plt.plot(prices_dataset_tail_50.High.values, color='black', label='high')
7plt.title('stock price')
8plt.xlabel('time [days]')
9plt.ylabel('price')
10plt.legend(loc='best')
11plt.show()
Hình ảnh trông khá rõ ràng và trực quan hơn rất nhiều.
Chúng ta sẽ bỏ đi cột DATE,Adj Close,Volume đi. Các cột đó không cần thiết cho quá trình dự đoán.
1
2prices_dataset_dropout = prices_dataset.drop(['Date','Adj Close','Volume'], 1)
Scale dữ liệu
Khi sử dụng ANN, chúng ta thông thường sẽ scale dữ liệu input về đoạn [-1,1]. Trong python, thư viện sklearn đã hỗ trợ cho chúng ta sẵn các hàm scale dữ liệu cần thiết.
1# Scale data
2def normalize_data(df):
3 min_max_scaler = MinMaxScaler()
4 df['Open'] = min_max_scaler.fit_transform(df.Open.values.reshape(-1,1))
5 df['High'] = min_max_scaler.fit_transform(df.High.values.reshape(-1,1))
6 df['Low'] = min_max_scaler.fit_transform(df.Low.values.reshape(-1,1))
7 df['Close'] = min_max_scaler.fit_transform(df.Close.values.reshape(-1,1))
8 return df
9
10prices_dataset_norm = normalize_data(prices_dataset_dropout)
Phân chia tập train và test.
Chúng ta sẽ chia dữ liệu thành 2 phần với 80% là train và 20% còn lại là test. Chọn seq_len=20, các bạn có thể test với các seq len khác, và sau đó chuyển dữ liệu về dạng numpy array để dễ dàng thực hiện các phép chuyển đổi.
1
2def generate_data(stock_ds, seq_len):
3 data_raw = stock_ds.as_matrix()
4 data = []
5
6 # create all possible sequences of length seq_len
7 for index in range(len(data_raw) - seq_len):
8 data.append(data_raw[index: index + seq_len])
9 return data
10
11#data as numpy array
12def generate_train_test(data_ds,split_percent=0.8):
13 print(len(data_ds))
14 data = np.asarray(data_ds)
15
16 data_size = len(data)
17 train_end = int(np.floor(split_percent*data_size))
18
19 x_train = data[:train_end,:-1,:]
20 y_train = data[:train_end,-1,:]
21
22
23
24 x_test = data[train_end:,:-1,:]
25 y_test = data[train_end:,-1,:]
26
27 return [x_train, y_train, x_test, y_test]
28
29
30
31seq_len = 20 # choose sequence length
32
33seq_prices_dataset = generate_data(prices_dataset_norm,seq_len)
34
35x_train, y_train, x_test, y_test = generate_train_test(seq_prices_dataset, 0.8)
36
37print('x_train.shape = ',x_train.shape)
38print('y_train.shape = ', y_train.shape)
39print('x_test.shape = ', x_test.shape)
40print('y_test.shape = ',y_test.shape)
Kết quả:
1x_train.shape = (13675, 19, 4)
2y_train.shape = (13675, 4)
3x_test.shape = (3419, 19, 4)
4y_test.shape = (3419, 4)
Xây dựng mô hình sử dụng keras
Ở đây mình sử dụng keras xây dựng mô hình ANN. Mô hình của mình xây dựng gồm:
1model = Sequential()
2
3model.add(LSTM(
4 input_dim=4,
5 output_dim=50,
6 return_sequences=True))
7model.add(Dropout(0.2))
8
9model.add(LSTM(
10 100,
11 return_sequences=False))
12model.add(Dropout(0.2))
13
14model.add(Dense(
15 output_dim=4))
16model.add(Activation('linear'))
17
18
19
20model.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])
21checkpoint = ModelCheckpoint(filepath='sp500_stockperdict.h5', verbose=1, save_best_only=True)
22hist = model.fit(x_train, y_train, epochs=300, batch_size=128, verbose=1, callbacks=[checkpoint], validation_split=0.2)
Sau một thời gian chạy, mình cũng thu được model. Các bạn quan tâm có thể download model của mình huấn luyện được tại https://drive.google.com/open?id=1ImHQM9yWmOjpF5tjmSI9oqAi5BORa9Rs . Tiến hành plot dữ liệu tập test lên xem kết quả như thế nào.
1
2model =load_model('sp500_stockperdict.h5')
3
4
5y_hat = model.predict(x_test)
6
7ft = 3 # 0 = open, 1 = highest, 2 =lowest , 3 = close
8
9plt.plot( y_test[:,ft], color='blue', label='target')
10
11plt.plot( y_hat[:,ft], color='red', label='prediction')
12
13plt.title('future stock prices')
14plt.xlabel('time [days]')
15plt.ylabel('normalized price')
16plt.legend(loc='best')
17
18plt.show()
19
20from sklearn.metrics import mean_squared_error
21
22# 0 = open, 1 = highest, 2 =lowest , 3 = close
23print("open error: ")
24print(mean_squared_error(y_test[:,0], y_hat[ :,0]))
25
26print("highest error: ")
27print(mean_squared_error(y_test[:,1], y_hat[ :,1]))
28
29print("lowest error: ")
30print(mean_squared_error(y_test[:,2], y_hat[ :,2]))
31
32print("close error: ")
33print(mean_squared_error(y_test[:,3], y_hat[ :,3]))
1open error:
20.0009739211460315127
3highest error:
40.0010539412808401607
5lowest error:
60.0010066509540756113
7close error:
80.0010840500965408758
Hiện đã có bản tensorflow 2 có tích hợp keras, mình update lại code
1
2from re import T
3import numpy as np
4# linear algebra
5import pandas as pd
6from tensorflow.keras.models import Sequential
7from tensorflow.keras.layers import Dense
8from tensorflow.keras.layers import LSTM
9from sklearn.preprocessing import MinMaxScaler
10import tensorflow as tf
11import joblib
12
13import matplotlib
14matplotlib.use('TkAgg')
15import matplotlib.pyplot as plt
16
17
18file_name ='GSPC.csv'
19
20
21prices_dataset = pd.read_csv(file_name, header=0)
22
23
24# prices_dataset_dropout = prices_dataset.drop(['Date','Adj Close','Volume'], 1)
25prices_dataset_dropout=prices_dataset.reset_index()['Close']
26
27
28scaler=MinMaxScaler(feature_range=(0,1))
29prices_dataset_norm=scaler.fit_transform(np.array(prices_dataset_dropout).reshape(-1,1))
30joblib.dump(scaler, 'scaler.alex')
31
32
33print(prices_dataset_norm[:10])
34
35
36def generate_data(stock_ds, seq_len,predict_next_t):
37 dataX, dataY = [], []
38 for i in range(len(stock_ds)-seq_len-1):
39 dataX.append(stock_ds[i:(i+seq_len)])
40 dataY.append(stock_ds[i + seq_len+predict_next_t])
41 return np.array(dataX), np.array(dataY)
42
43#data as numpy array
44def generate_train_test(data_x,data_y,split_percent=0.8):
45
46 train_end = int(np.floor(split_percent*data_x.shape[0]))
47
48 x_train,x_test=data_x[:train_end,:],data_x[train_end:,:]
49 y_train,y_test = data_y[:train_end],data_y[train_end:]
50 return x_train,y_train,x_test,y_test
51
52
53
54seq_len = 100 # choose sequence length
55predict_next_t = 1 # 0 is next date, 1 is 2 next date
56
57data_x, data_y = generate_data(prices_dataset_norm,seq_len,predict_next_t)
58
59x_train,y_train,x_test,y_test = generate_train_test(data_x,data_y, 0.8)
60
61
62x_train =x_train.reshape(x_train.shape[0],x_train.shape[1] , 1)
63x_test = x_test.reshape(x_test.shape[0],x_test.shape[1] , 1)
64print('x_train.shape = ',x_train.shape)
65print('y_train.shape = ', y_train.shape)
66print('x_test.shape = ', x_test.shape)
67print('y_test.shape = ',y_test.shape)
68
69
70
71model = Sequential()
72
73 # input_dim=4,
74 # output_dim=50,
75model.add(LSTM(units=100,input_shape=x_train.shape[1:],
76 return_sequences=True))
77
78model.add(LSTM(
79 100,
80 return_sequences=False))
81model.add(Dense(1))
82
83
84model.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])
85checkpoint = tf.keras.callbacks.ModelCheckpoint(filepath='my_model_stock.h5', verbose=1, save_best_only=True)
86hist = model.fit(x_train, y_train, epochs=3, batch_size=64, verbose=1, callbacks=[checkpoint], validation_split=0.2)
87
88from tensorflow.keras.models import load_model
89print('load model')
90model =load_model('my_model_stock.h5')
91
92print('predict')
93y_test = y_test.reshape(y_test.shape[0])
94# train_predict=model.predict(x_train)
95test_predict=model.predict(x_test)
96print('invert')
97print(y_test.shape)
98# train_predict=scaler.inverse_transform(train_predict)
99
100# scaler = joblib.load('scaler.alex')
101
102y_hat=scaler.inverse_transform(test_predict)
103y_test=scaler.inverse_transform(y_test.reshape(-1, 1))
104print(y_hat.shape)
105# y_hat = model.predict(x_test)
106# import matplotlib
107# matplotlib.use('GTKAgg')
108# print('plot')
109
110plt.plot( y_test, color='blue', label='target')
111
112plt.plot( y_hat, color='red', label='prediction')
113print('plot complete')
114plt.title('future stock prices')
115plt.xlabel('time [days]')
116plt.ylabel('normalized price')
117plt.legend(loc='best')
118print('plot show')
119plt.savefig("mygraph.png")
120plt.show()
Kết quả của mô hình trông khá tốt, về hình dạng thì khá tương đồng với kết quả. Chúng ta có thể cải tiến model bằng cách nâng số lượng layer/ hidden node.
Cảm ơn các bạn đã theo dõi. Hẹn gặp bạn ở các bài viết tiếp theo.
Comments