預測股市的走勢是最困難的事情之一。影響預測的因素不少 - 包括物理因素與心理因素,理性行爲和非理性行爲等。全部這些因素結合在一塊兒共同致使股價波動,很難以高精度預測。python
咱們是否能夠將機器學習做爲該領域的遊戲規則改變者嗎?利用一些特性,好比關於一個組織的最新公告,他們的季度收入結果等功能,機器學習技術有可能發掘出咱們之前沒有看到的模式和看法,而且能夠用來作出準確無誤的預測。算法
在本文中,咱們將使用有關上市公司股票價格的歷史數據。咱們將使用多種機器學習算法來預測該公司的將來股票價格,從平均算法和線性迴歸等簡單的算法開始,而後轉向Auto ARIMA和LSTM等高級技術。網絡
本文背後的核心思想是展現如何實現這些算法。我將簡要介紹該技術並提供相關連接,以便在必要時瞭解這些概念。app
咱們很快就會深刻到本文的實現部分,但首先要肯定咱們要解決的問題。從廣義上講,股票市場分析分爲兩部分 - 基礎分析和技術分析。機器學習
你可能已經猜到了,咱們的重點將放在技術分析部分。咱們將使用Quandl的數據集(你能夠在這裏查找各類股票的歷史數據),對於這個特定的項目,我使用了「 塔塔全球飲料 」 的數據。是時候讓咱們動起來了!性能
注意:有關文章的數據集我將在文章最後放出學習
首先咱們先加載數據集,定義問題的目標變量:測試
import pandas as pd
import numpy as npspa
import matplotlib.pyplot as plt
%matplotlib inline設計
from matplotlib.pylab import rcParams
rcParams['figure.figsize'] = 20,10
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler(feature_range=(0, 1))
df = pd.read_csv('NSE-TATAGLOBAL(1).csv')
df.head()
數據集中有多個變量 - date,open,high,low,last,close,totaltradequantity和turnover。
另外一個須要注意的重要事項是,市場在週末和公共假期關閉。再次注意上表,一些日期值缺失 - 2/10/201,6/10/201,7/10/201。在這些日期中,2號是法定假日,6號和7號是週末。
損益的計算一般由當天股票的收盤價肯定,所以咱們將收盤價視爲目標變量。讓咱們繪製目標變量,以瞭解它在咱們的數據中是如何造成的:
df['Date'] = pd.to_datetime(df.Date,format='%Y-%m-%d')
df.index = df['Date']
plt.figure(figsize=(16,8))
plt.plot(df['Close'], label='Close Price history')
!](http://upload-images.jianshu....
在接下來的部分中,咱們將探索這些變量,並使用不一樣的技術來預測股票的每日收盤價。
「平均」很容易成爲咱們平常生活中最經常使用的詞彙之一。例如,計算平均分來肯定總體性能,或者找出過去幾天的平均溫度以瞭解今天的溫度 - 這些都是咱們常常作的例行工做。所以,這是一個很好的起點,能夠用於咱們的數據集進行預測。
天天的預計收盤價將是一組先前觀測值的平均值。咱們將使用移動平均技術而不是使用簡單平均值,該技術爲每一個預測使用最新的一組值。換句話說,對於每一個後續步驟,在從集合中移除最老的觀測值的同時考慮預測值。下面是一個簡單的圖形,能夠幫助你更清晰地理解這一點。
咱們將在咱們的數據集上實現此技術。第一步是建立一個僅包含Date和Close price列的DataFrame,而後將其拆分爲訓練集和驗證集以驗證咱們的預測。
data = df.sort_index(ascending=True, axis=0)
new_data = pd.DataFrame(index=range(0,len(df)),columns=['Date', 'Close'])
for i in range(0,len(data)):
new_data'Date' = data'Date'
new_data'Close' = data'Close'
在將數據拆分爲訓練集和驗證集時,咱們不能使用隨機拆分,由於這會破壞時間組件。因此這裏我把去年的數據和以前四年的數據進行了驗證。
train = new_data[:987]
valid = new_data[987:]
new_data.shape, train.shape, valid.shape
((1235, 2), (987, 2), (248, 2))
train['Date'].min(), train['Date'].max(), valid['Date'].min(), valid['Date'].max()
(Timestamp('2013-10-08 00:00:00'),
Timestamp('2017-10-06 00:00:00'),
Timestamp('2017-10-09 00:00:00'),
Timestamp('2018-10-08 00:00:00'))
下一步是爲驗證集建立預測,並使用實際值檢查RMSE。
preds = []
for i in range(0,248):
a = train'Close'.sum() + sum(preds)
b = a/248
preds.append(b)
rms=np.sqrt(np.mean(np.power((np.array(valid['Close'])-preds),2)))
rms
104.51415465984348
僅檢查RMSE並不能幫助咱們理解模型的執行方式。讓咱們把它形象化來得到更直觀的理解。所以,這是預測值與實際值的關係圖。
valid['Predictions'] = 0
valid['Predictions'] = preds
plt.plot(train['Close'])
plt.plot(valid[['Close', 'Predictions']])
RMSE值接近105,但結果不是頗有但願(能夠從圖中看出)。預測值與驗證集中的觀測值具備相同的範圍(最初存在增長趨勢,而後緩慢減少)。
在下一節中,咱們將介紹兩種經常使用的機器學習技術 - 線性迴歸和kNN,並瞭解它們在咱們股票市場數據上的表現。
能夠在此數據上實現的最基本的機器學習算法是線性迴歸。線性迴歸模型返回一個肯定自變量和因變量之間關係的方程。
線性迴歸的方程能夠寫成:
這裏,x1,x2,... .Xň表明獨立變量,而係數θ1,θ2,...θÑ表示的權重。
對於咱們的問題描述,咱們沒有一組自變量。咱們只有日期而已。讓咱們使用日期列來提取諸如 - 日,月,年,星期一/星期五等特徵,而後擬合線性迴歸模型。
咱們將首先按升序對數據集進行排序,而後建立一個單獨的數據集,以便建立的任何新要素都不會影響原始數據。
df['Date'] = pd.to_datetime(df.Date,format='%Y-%m-%d')
df.index = df['Date']
data = df.sort_index(ascending=True, axis=0)
new_data = pd.DataFrame(index=range(0,len(df)),columns=['Date', 'Close'])
for i in range(0,len(data)):
new_data'Date' = data'Date'
new_data'Close' = data'Close'
from fastai.structured import add_datepart
add_datepart(new_data, 'Date')
new_data.drop('Elapsed', axis=1, inplace=True) #elapsed will be the time stamp
這會建立如下特徵:
‘Year’, ‘Month’, ‘Week’, ‘Day’, ‘Dayofweek’, ‘Dayofyear’, ‘Ismonthend’, ‘Ismonthstart’, ‘Isquarterend’, ‘Isquarterstart’, ‘Isyearend’, and ‘Isyearstart’.
注意:我使用了fastai庫中的add_datepart。若是你沒有安裝它,只需使用命令pip install fastai。或者,你能夠在python中使用簡單的for循環建立這個功能。我在下面展現了一個例子。
除此以外,咱們能夠添加咱們本身認爲與預測相關的特徵。例如,個人假設是,本週的第一天和最後一天可能會影響股票的收盤價,而且遠遠超過其餘日子。因此我建立了一個特徵,能夠肯定某一天是週一/週五仍是週二/週三/週四。這可使用如下的代碼行完成:
new_data['mon_fri'] = 0
for i in range(0,len(new_data)):
if (new_data'Dayofweek' == 0 or new_data'Dayofweek' == 4):
new_data'mon_fri' = 1
else:
new_data'mon_fri' = 0
若是星期幾等於0或4,則列值將爲1,不然爲0。一樣的,你能夠建立多個特徵。若是你對能夠幫助預測股票價格的功能有一些想法,請在評論區分享。
咱們如今將數據拆分爲訓練集和驗證集,以檢查模型的性能。
train = new_data[:987]
valid = new_data[987:]
x_train = train.drop('Close', axis=1)
y_train = train['Close']
x_valid = valid.drop('Close', axis=1)
y_valid = valid['Close']
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(x_train,y_train)
preds = model.predict(x_valid)
rms=np.sqrt(np.mean(np.power((np.array(y_valid)-np.array(preds)),2)))
rms
121.16291596523156
RMSE值高於以前的技術,這清楚地代表線性迴歸表現不佳。讓咱們看一下圖表,並理解爲何線性迴歸作的很差:
valid['Predictions'] = 0
valid['Predictions'] = preds
valid.index = new_data[987:].index
train.index = new_data[:987].index
plt.plot(train['Close'])
plt.plot(valid[['Close', 'Predictions']])
線性迴歸是一種簡單的技術,而且很容易解釋,但有一些明顯的缺點。使用迴歸算法的一個問題是模型與日期列和月份列過分匹配。模型將考慮一個月前的同一日期或一年前的同一日期/月的值,而不是從預測的角度考慮之前的值。
從上圖能夠看出,2016年1月和2017年1月,股價出現下跌。該模型已預測2018年1月的狀況相同。線性迴歸技術能夠很好地解決諸如大型超市的銷售問題,在這些問題中獨立特徵對於肯定目標值是有用的。
這裏可使用的另外一個有趣的ML算法是KNN(K近鄰)。KNN基於自變量找到新數據點和舊數據點之間的類似性。讓我用一個簡單的例子解釋一下。
考慮11我的的身高和年齡。根據給定的特徵('年齡Age'和'身高Height'),表格能夠用圖形格式表示,以下所示:
爲了肯定ID#11的權重,K-NN考慮該ID的最近鄰的權重。ID#11的權重預計是其鄰居的平均值。若是咱們如今考慮三個鄰居(k = 3),ID#11的權重將是=(77 + 72 + 60)/ 3 = 69.66千克。
from sklearn import neighbors
from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler(feature_range=(0, 1))
使用上一節中相同的訓練集和驗證集:
x_train_scaled = scaler.fit_transform(x_train)
x_train = pd.DataFrame(x_train_scaled)
x_valid_scaled = scaler.fit_transform(x_valid)
x_valid = pd.DataFrame(x_valid_scaled)
params = {'n_neighbors':[2,3,4,5,6,7,8,9]}
knn = neighbors.KNeighborsRegressor()
model = GridSearchCV(knn, params, cv=5)
model.fit(x_train,y_train)
preds = model.predict(x_valid)
rms=np.sqrt(np.mean(np.power((np.array(y_valid)-np.array(preds)),2)))
rms
115.17086550026721
RMSE值沒有太大差別,但預測值和實際值的圖應提供一個更清晰的理解。
valid['Predictions'] = 0
valid['Predictions'] = preds
plt.plot(valid[['Close', 'Predictions']])
plt.plot(train['Close'])
RMSE值幾乎與線性迴歸模型相似,而且圖表也顯示了相同的模式。與線性迴歸同樣,KNN也肯定了2018年1月的降低,由於這是過去幾年的形式。咱們能夠有把握地說,迴歸算法在這個數據集上表現不佳。
讓咱們繼續看看一些時間序列預測技術,以瞭解它們在面對股票價格預測挑戰時的表現。
ARIMA是一種很是流行的時間序列預測統計方法。ARIMA模型考慮了過去的值來預測將來的價值。ARIMA有三個重要參數:
ARIMA的參數調整會消耗大量時間。所以,咱們將使用auto ARIMA,它自動選擇(p,q,d)提供最小錯誤的的最佳組合。
from pyramid.arima import auto_arima
data = df.sort_index(ascending=True, axis=0)
train = data[:987]
valid = data[987:]
training = train['Close']
validation = valid['Close']
model = auto_arima(training, start_p=1, start_q=1,max_p=3, max_q=3, m=12,start_P=0, seasonal=True,d=1, D=1, trace=True,error_action='ignore',suppress_warnings=True)
model.fit(training)
forecast = model.predict(n_periods=248)
forecast = pd.DataFrame(forecast,index = valid.index,columns=['Prediction'])
rms=np.sqrt(np.mean(np.power((np.array(valid['Close'])-np.array(forecast['Prediction'])),2)))
rms
44.954584993246954
plt.plot(火車[ '關閉'])
plt.plot(有效[ '關閉'])
plt.plot(預測[ '預測'])
如前所述,auto ARIMA模型使用過去的數據來理解時間序列中的模式。使用這些值,模型得到了該系列中的增加趨勢。雖然使用這種技術的預測遠比先前實現的機器學習模型的預測好,但這些預測仍然沒有接近實際值。
從圖中能夠看出,該模型已經捕捉到了該系列中的一個趨勢,但並無關注季節性部分。在下一節中,咱們將實現一個時間序列模型,而這個模型考慮了系列的趨勢和季節性。
有許多時間序列技術能夠在股票預測數據集上實現,可是大多數這些技術在擬合模型以前須要大量的數據預處理。由Facebook設計和開創的Prophet是一個時間序列預測庫,它不須要數據預處理,實現起來也很是簡單。Prophet的輸入是一個包含兩列的數據框:date和target(ds和y)。
Prophet試圖獲取過去數據中的季節性,並在數據集很大時能夠進行很好的工做。
from fbprophet import Prophet
new_data = pd.DataFrame(index=range(0,len(df)),columns=['Date', 'Close'])
for i in range(0,len(data)):
new_data'Date' = data'Date'
new_data'Close' = data'Close'
new_data['Date'] = pd.to_datetime(new_data.Date,format='%Y-%m-%d')
new_data.index = new_data['Date']
new_data.rename(columns={'Close': 'y', 'Date': 'ds'}, inplace=True)
train = new_data[:987]
valid = new_data[987:]
model = Prophet()
model.fit(train)
close_prices = model.make_future_dataframe(periods=len(valid))
forecast = model.predict(close_prices)
forecast_valid = forecast'yhat'
rms=np.sqrt(np.mean(np.power((np.array(valid['y'])-np.array(forecast_valid)),2)))
rms
57.494461930575149
valid['Predictions'] = 0
valid['Predictions'] = forecast_valid.values
plt.plot(train['y'])
plt.plot(valid[['y', 'Predictions']])
Prophet(與大多數時間序列預測技術同樣)試圖從過去的數據中獲取趨勢性和季節性。此模型一般在時間序列數據集上表現良好,但在這種狀況下沒法達到它的名譽。
事實證實,股票價格沒有特定的趨勢性或季節性。它在很大程度上取決於市場目前的狀況,從而價格會上漲和下跌。所以,像ARIMA,SARIMA和Prophet這樣的預測技術對於這個特定問題不會顯示出良好的結果。
讓咱們繼續嘗試另外一種先進技術 - 長短時記憶(LSTM)。
LSTM普遍用於序列預測問題,而且已被證實是很是有效的。他們很是有效的緣由是由於LSTM可以存儲過去重要的信息,並忘記不重要的信息。LSTM有三個門:
如今,讓咱們將LSTM實現爲一個黑盒子,並檢查它在咱們的特定數據上的性能。
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import Dense, Dropout, LSTM
data = df.sort_index(ascending=True, axis=0)
new_data = pd.DataFrame(index=range(0,len(df)),columns=['Date', 'Close'])
for i in range(0,len(data)):
new_data'Date' = data'Date'
new_data'Close' = data'Close'
new_data.index = new_data.Date
new_data.drop('Date', axis=1, inplace=True)
dataset = new_data.values
train = dataset[0:987,:]
valid = dataset[987:,:]
scaler = MinMaxScaler(feature_range=(0, 1))
scaled_data = scaler.fit_transform(dataset)
x_train, y_train = [], []
for i in range(60,len(train)):
x_train.append(scaled_data[i-60:i,0])
y_train.append(scaled_data[i,0])
x_train, y_train = np.array(x_train), np.array(y_train)
x_train = np.reshape(x_train, (x_train.shape[0],x_train.shape[1],1))
model = Sequential()
model.add(LSTM(units=50, return_sequences=True, input_shape=(x_train.shape[1],1)))
model.add(LSTM(units=50))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(x_train, y_train, epochs=1, batch_size=1, verbose=2)
inputs = new_data[len(new_data) - len(valid) - 60:].values
inputs = inputs.reshape(-1,1)
inputs = scaler.transform(inputs)
X_test = []
for i in range(60,inputs.shape[0]):
X_test.append(inputs[i-60:i,0])
X_test = np.array(X_test)
X_test = np.reshape(X_test, (X_test.shape[0],X_test.shape[1],1))
closing_price = model.predict(X_test)
closing_price = scaler.inverse_transform(closing_price)
rms=np.sqrt(np.mean(np.power((valid-closing_price),2)))
rms
11.772259608962642
train = new_data[:987]
valid = new_data[987:]
valid['Predictions'] = closing_price
plt.plot(train['Close'])
plt.plot(valid[['Close','Predictions']])
LSTM模型能夠根據不一樣的參數進行調整,例如改變LSTM層的數量,添加dropout值或增長epoch的數量。但LSTM的預測是否足以肯定股價是漲仍是降?固然不是!
正如我在文章開頭提到的那樣,股票價格受到有關公司的新聞以及其餘因素的影響,如公司的非貨幣化或合併/分拆。還有一些無形因素,每每是事先沒法預測的。
時間序列預測是一個很是有趣的領域,正如我在撰寫這些文章時所認識到的那樣。在社區中有一種見解,認爲它是一個很是複雜的領域,雖然有些的確比較複雜,可是一旦掌握了基本技術,也就不那麼困難了。
本文做者使用了六種方法來進行了對股票漲跌的預測,並從結果中分析了每一個算法用於時間序列模型的優劣,而且從圖中能夠看出LSTM方法是擬合最好的一種方法,可是股票市場須要考慮的因素有不少,並非只須要幾個關鍵的特徵就能夠預測的,咱們能夠根據之前的數據,對算法進行驗證,但使用算法去預測將來的股票的漲跌,仍是有一些風險的,因此仍是要謹慎的去使用這些算法。至少如今沒有一種算法能夠百分之百的去預測將來股票的時間序列模型算法,仍是先暫時的用算法去不斷的訓練,直到將來技術成熟的一天。
Stock Prices Prediction Using Machine Learning and Deep Learning Techniques (with Python codes)