介紹預(yù)測(cè)股市的走勢(shì)是最困難的事情之一。影響預(yù)測(cè)的因素很多 - 包括物理因素與心理因素,理性行為和非理性行為等。所有這些因素結(jié)合在一起共同導(dǎo)致股價(jià)波動(dòng),很難以高精度預(yù)測(cè)。 我們是否可以將機(jī)器學(xué)習(xí)作為該領(lǐng)域的游戲規(guī)則改變者嗎?利用一些特性,比如關(guān)于一個(gè)組織的最新公告,他們的季度收入結(jié)果等功能,機(jī)器學(xué)習(xí)技術(shù)有可能發(fā)掘出我們以前沒有看到的模式和見解,并且可以用來做出準(zhǔn)確無誤的預(yù)測(cè)。 在本文中,我們將使用有關(guān)上市公司股票價(jià)格的歷史數(shù)據(jù)。我們將使用多種機(jī)器學(xué)習(xí)算法來預(yù)測(cè)該公司的未來股票價(jià)格,從平均算法和線性回歸等簡(jiǎn)單的算法開始,然后轉(zhuǎn)向Auto ARIMA和LSTM等高級(jí)技術(shù)。 本文背后的核心思想是展示如何實(shí)現(xiàn)這些算法。我將簡(jiǎn)要介紹該技術(shù)并提供相關(guān)鏈接,以便在必要時(shí)了解這些概念。 問題描述我們很快就會(huì)深入到本文的實(shí)現(xiàn)部分,但首先要確定我們要解決的問題。從廣義上講,股票市場(chǎng)分析分為兩部分 - 基礎(chǔ)分析和技術(shù)分析。
你可能已經(jīng)猜到了,我們的重點(diǎn)將放在技術(shù)分析部分。我們將使用Quandl的數(shù)據(jù)集(你可以在這里查找各種股票的歷史數(shù)據(jù)),對(duì)于這個(gè)特定的項(xiàng)目,我使用了“ 塔塔全球飲料 ” 的數(shù)據(jù)。是時(shí)候讓我們動(dòng)起來了! 注意:有關(guān)文章的數(shù)據(jù)集我將在文章最后放出 首先我們先加載數(shù)據(jù)集,定義問題的目標(biāo)變量: 導(dǎo)入包import pandas as pd 在筆記本上繪圖import matplotlib.pyplot as plt 設(shè)置圖的大小from matplotlib.pylab import rcParams 規(guī)范數(shù)據(jù)from sklearn.preprocessing import MinMaxScaler 讀取文件df = pd.read_csv('NSE-TATAGLOBAL(1).csv') 打印頭部數(shù)據(jù)df.head() 數(shù)據(jù)集中有多個(gè)變量 - date,open,high,low,last,close,totaltradequantity和turnover。
另一個(gè)需要注意的重要事項(xiàng)是,市場(chǎng)在周末和公共假期關(guān)閉。再次注意上表,一些日期值缺失 - 2/10/201,6/10/201,7/10/201。在這些日期中,2號(hào)是法定假日,6號(hào)和7號(hào)是周末。 損益的計(jì)算通常由當(dāng)天股票的收盤價(jià)確定,因此我們將收盤價(jià)視為目標(biāo)變量。讓我們繪制目標(biāo)變量,以了解它在我們的數(shù)據(jù)中是如何形成的: 將索引設(shè)置為日期df['Date'] = pd.to_datetime(df.Date,format='%Y-%m-%d') 畫圖plt.figure(figsize=(16,8)) 在接下來的部分中,我們將探索這些變量,并使用不同的技術(shù)來預(yù)測(cè)股票的每日收盤價(jià)。 1.移動(dòng)平均法介紹“平均”很容易成為我們?nèi)粘I钪凶畛S玫脑~匯之一。例如,計(jì)算平均分來確定整體性能,或者找出過去幾天的平均溫度以了解今天的溫度 - 這些都是我們經(jīng)常做的例行工作。因此,這是一個(gè)很好的起點(diǎn),可以用于我們的數(shù)據(jù)集進(jìn)行預(yù)測(cè)。 每天的預(yù)計(jì)收盤價(jià)將是一組先前觀測(cè)值的平均值。我們將使用移動(dòng)平均技術(shù)而不是使用簡(jiǎn)單平均值,該技術(shù)為每個(gè)預(yù)測(cè)使用最新的一組值。換句話說,對(duì)于每個(gè)后續(xù)步驟,在從集合中移除最老的觀測(cè)值的同時(shí)考慮預(yù)測(cè)值。下面是一個(gè)簡(jiǎn)單的圖形,可以幫助你更清晰地理解這一點(diǎn)。 我們將在我們的數(shù)據(jù)集上實(shí)現(xiàn)此技術(shù)。第一步是創(chuàng)建一個(gè)僅包含Date和Close price列的DataFrame,然后將其拆分為訓(xùn)練集和驗(yàn)證集以驗(yàn)證我們的預(yù)測(cè)。 Python代碼使用日期和目標(biāo)變量創(chuàng)建dataframedata = df.sort_index(ascending=True, axis=0) for i in range(0,len(data)): 在將數(shù)據(jù)拆分為訓(xùn)練集和驗(yàn)證集時(shí),我們不能使用隨機(jī)拆分,因?yàn)檫@會(huì)破壞時(shí)間組件。所以這里我把去年的數(shù)據(jù)和之前四年的數(shù)據(jù)進(jìn)行了驗(yàn)證。 分隔為訓(xùn)練集和驗(yàn)證集train = new_data[:987] new_data.shape, train.shape, valid.shape train['Date'].min(), train['Date'].max(), valid['Date'].min(), valid['Date'].max() (Timestamp('2013-10-08 00:00:00'), 下一步是為驗(yàn)證集創(chuàng)建預(yù)測(cè),并使用實(shí)際值檢查RMSE。 做出預(yù)測(cè)preds = [] 結(jié)果計(jì)算 rmserms=np.sqrt(np.mean(np.power((np.array(valid['Close'])-preds),2))) 104.51415465984348 僅檢查RMSE并不能幫助我們理解模型的執(zhí)行方式。讓我們把它形象化來獲得更直觀的理解。因此,這是預(yù)測(cè)值與實(shí)際值的關(guān)系圖。 畫圖valid['Predictions'] = 0 推論RMSE值接近105,但結(jié)果不是很有希望(可以從圖中看出)。預(yù)測(cè)值與驗(yàn)證集中的觀測(cè)值具有相同的范圍(最初存在增加趨勢(shì),然后緩慢減?。?。 在下一節(jié)中,我們將介紹兩種常用的機(jī)器學(xué)習(xí)技術(shù) - 線性回歸和kNN,并了解它們?cè)谖覀児善笔袌?chǎng)數(shù)據(jù)上的表現(xiàn)。 2.線性回歸介紹可以在此數(shù)據(jù)上實(shí)現(xiàn)的最基本的機(jī)器學(xué)習(xí)算法是線性回歸。線性回歸模型返回一個(gè)確定自變量和因變量之間關(guān)系的方程。 線性回歸的方程可以寫成: 這里,x1,x2,... .Xň代表獨(dú)立變量,而系數(shù)θ1,θ2,...θ?表示的權(quán)重。 對(duì)于我們的問題描述,我們沒有一組自變量。我們只有日期而已。讓我們使用日期列來提取諸如 - 日,月,年,星期一/星期五等特征,然后擬合線性回歸模型。 Python代碼我們將首先按升序?qū)?shù)據(jù)集進(jìn)行排序,然后創(chuàng)建一個(gè)單獨(dú)的數(shù)據(jù)集,以便創(chuàng)建的任何新要素都不會(huì)影響原始數(shù)據(jù)。 將索引設(shè)置為日期值df['Date'] = pd.to_datetime(df.Date,format='%Y-%m-%d') 排序data = df.sort_index(ascending=True, axis=0) 創(chuàng)建單獨(dú)的數(shù)據(jù)集new_data = pd.DataFrame(index=range(0,len(df)),columns=['Date', 'Close']) for i in range(0,len(data)): 創(chuàng)建功能from fastai.structured import add_datepart 這會(huì)創(chuàng)建以下特征: ‘Year’, ‘Month’, ‘Week’, ‘Day’, ‘Dayofweek’, ‘Dayofyear’, ‘Ismonthend’, ‘Ismonthstart’, ‘Isquarterend’, ‘Isquarterstart’, ‘Isyearend’, and ‘Isyearstart’. 注意:我使用了fastai庫中的add_datepart。如果你沒有安裝它,只需使用命令pip install fastai?;蛘?,你可以在python中使用簡(jiǎn)單的for循環(huán)創(chuàng)建這個(gè)功能。我在下面展示了一個(gè)例子。 除此之外,我們可以添加我們自己認(rèn)為與預(yù)測(cè)相關(guān)的特征。例如,我的假設(shè)是,本周的第一天和最后一天可能會(huì)影響股票的收盤價(jià),并且遠(yuǎn)遠(yuǎn)超過其他日子。所以我創(chuàng)建了一個(gè)特征,可以確定某一天是周一/周五還是周二/周三/周四。這可以使用以下的代碼行完成: new_data['mon_fri'] = 0 如果星期幾等于0或4,則列值將為1,否則為0。同樣的,你可以創(chuàng)建多個(gè)特征。如果你對(duì)可以幫助預(yù)測(cè)股票價(jià)格的功能有一些想法,請(qǐng)?jiān)谠u(píng)論區(qū)分享。 我們現(xiàn)在將數(shù)據(jù)拆分為訓(xùn)練集和驗(yàn)證集,以檢查模型的性能。 拆分為訓(xùn)練集與驗(yàn)證集train = new_data[:987] x_train = train.drop('Close', axis=1) 實(shí)現(xiàn)線性回歸from sklearn.linear_model import LinearRegression 結(jié)果做出預(yù)測(cè)并找rmsepreds = model.predict(x_valid) 121.16291596523156 RMSE值高于之前的技術(shù),這清楚地表明線性回歸表現(xiàn)不佳。讓我們看一下圖表,并理解為什么線性回歸做的不好: 畫圖valid['Predictions'] = 0 valid.index = new_data[987:].index plt.plot(train['Close']) 推論線性回歸是一種簡(jiǎn)單的技術(shù),并且很容易解釋,但有一些明顯的缺點(diǎn)。使用回歸算法的一個(gè)問題是模型與日期列和月份列過度匹配。模型將考慮一個(gè)月前的同一日期或一年前的同一日期/月的值,而不是從預(yù)測(cè)的角度考慮以前的值。 從上圖可以看出,2016年1月和2017年1月,股價(jià)出現(xiàn)下跌。該模型已預(yù)測(cè)2018年1月的情況相同。線性回歸技術(shù)可以很好地解決諸如大型超市的銷售問題,在這些問題中獨(dú)立特征對(duì)于確定目標(biāo)值是有用的。 3.K-近鄰介紹這里可以使用的另一個(gè)有趣的ML算法是KNN(K近鄰)。KNN基于自變量找到新數(shù)據(jù)點(diǎn)和舊數(shù)據(jù)點(diǎn)之間的相似性。讓我用一個(gè)簡(jiǎn)單的例子解釋一下。 考慮11個(gè)人的身高和年齡。根據(jù)給定的特征('年齡Age'和'身高Height'),表格可以用圖形格式表示,如下所示: 為了確定ID#11的權(quán)重,K-NN考慮該ID的最近鄰的權(quán)重。ID#11的權(quán)重預(yù)計(jì)是其鄰居的平均值。如果我們現(xiàn)在考慮三個(gè)鄰居(k = 3),ID#11的權(quán)重將是=(77 + 72 + 60)/ 3 = 69.66千克。 PYthon代碼導(dǎo)入庫from sklearn import neighbors 使用上一節(jié)中相同的訓(xùn)練集和驗(yàn)證集: 尺度數(shù)據(jù)x_train_scaled = scaler.fit_transform(x_train) 使用gridsearch查找最佳參數(shù)params = {'n_neighbors':[2,3,4,5,6,7,8,9]} 擬合模型并做出預(yù)測(cè)model.fit(x_train,y_train) 結(jié)果查看RMSe值rms=np.sqrt(np.mean(np.power((np.array(y_valid)-np.array(preds)),2))) 115.17086550026721 RMSE值沒有太大差異,但預(yù)測(cè)值和實(shí)際值的圖應(yīng)提供一個(gè)更清晰的理解。 畫圖valid['Predictions'] = 0 推論RMSE值幾乎與線性回歸模型類似,并且圖表也顯示了相同的模式。與線性回歸一樣,KNN也確定了2018年1月的下降,因?yàn)檫@是過去幾年的形式。我們可以有把握地說,回歸算法在這個(gè)數(shù)據(jù)集上表現(xiàn)不佳。 讓我們繼續(xù)看看一些時(shí)間序列預(yù)測(cè)技術(shù),以了解它們?cè)诿鎸?duì)股票價(jià)格預(yù)測(cè)挑戰(zhàn)時(shí)的表現(xiàn)。 4.Auto ARIMA介紹ARIMA是一種非常流行的時(shí)間序列預(yù)測(cè)統(tǒng)計(jì)方法。ARIMA模型考慮了過去的值來預(yù)測(cè)未來的價(jià)值。ARIMA有三個(gè)重要參數(shù):
ARIMA的參數(shù)調(diào)整會(huì)消耗大量時(shí)間。因此,我們將使用auto ARIMA,它自動(dòng)選擇(p,q,d)提供最小錯(cuò)誤的的最佳組合。 Python代碼from pyramid.arima import auto_arima data = df.sort_index(ascending=True, axis=0) train = data[:987] training = train['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) forecast = model.predict(n_periods=248) 結(jié)果rms=np.sqrt(np.mean(np.power((np.array(valid['Close'])-np.array(forecast['Prediction'])),2))) 44.954584993246954 畫圖plt.plot(火車[ '關(guān)閉']) 推論如前所述,auto ARIMA模型使用過去的數(shù)據(jù)來理解時(shí)間序列中的模式。使用這些值,模型獲得了該系列中的增長趨勢(shì)。雖然使用這種技術(shù)的預(yù)測(cè)遠(yuǎn)比先前實(shí)現(xiàn)的機(jī)器學(xué)習(xí)模型的預(yù)測(cè)好,但這些預(yù)測(cè)仍然沒有接近實(shí)際值。 從圖中可以看出,該模型已經(jīng)捕捉到了該系列中的一個(gè)趨勢(shì),但并沒有關(guān)注季節(jié)性部分。在下一節(jié)中,我們將實(shí)現(xiàn)一個(gè)時(shí)間序列模型,而這個(gè)模型考慮了系列的趨勢(shì)和季節(jié)性。 5.Prophet介紹有許多時(shí)間序列技術(shù)可以在股票預(yù)測(cè)數(shù)據(jù)集上實(shí)現(xiàn),但是大多數(shù)這些技術(shù)在擬合模型之前需要大量的數(shù)據(jù)預(yù)處理。由Facebook設(shè)計(jì)和開創(chuàng)的Prophet是一個(gè)時(shí)間序列預(yù)測(cè)庫,它不需要數(shù)據(jù)預(yù)處理,實(shí)現(xiàn)起來也非常簡(jiǎn)單。Prophet的輸入是一個(gè)包含兩列的數(shù)據(jù)框:date和target(ds和y)。 Prophet試圖獲取過去數(shù)據(jù)中的季節(jié)性,并在數(shù)據(jù)集很大時(shí)可以進(jìn)行很好的工作。 Python代碼導(dǎo)入 prophetfrom fbprophet import Prophet 創(chuàng)建 dataframenew_data = pd.DataFrame(index=range(0,len(df)),columns=['Date', 'Close']) for i in range(0,len(data)): new_data['Date'] = pd.to_datetime(new_data.Date,format='%Y-%m-%d') 準(zhǔn)備數(shù)據(jù)new_data.rename(columns={'Close': 'y', 'Date': 'ds'}, inplace=True) 訓(xùn)練和驗(yàn)證train = new_data[:987] 使用合適的模型model = Prophet() 預(yù)測(cè)close_prices = model.make_future_dataframe(periods=len(valid)) 結(jié)果查看rmseforecast_valid = forecast['yhat'][987:] 57.494461930575149 畫圖valid['Predictions'] = 0 plt.plot(train['y']) 推論Prophet(與大多數(shù)時(shí)間序列預(yù)測(cè)技術(shù)一樣)試圖從過去的數(shù)據(jù)中獲取趨勢(shì)性和季節(jié)性。此模型通常在時(shí)間序列數(shù)據(jù)集上表現(xiàn)良好,但在這種情況下無法達(dá)到它的名譽(yù)。 事實(shí)證明,股票價(jià)格沒有特定的趨勢(shì)性或季節(jié)性。它在很大程度上取決于市場(chǎng)目前的情況,從而價(jià)格會(huì)上漲和下跌。因此,像ARIMA,SARIMA和Prophet這樣的預(yù)測(cè)技術(shù)對(duì)于這個(gè)特定問題不會(huì)顯示出良好的結(jié)果。 讓我們繼續(xù)嘗試另一種先進(jìn)技術(shù) - 長短時(shí)記憶(LSTM)。 6.長短時(shí)記憶(LSTM)介紹LSTM廣泛用于序列預(yù)測(cè)問題,并且已被證明是非常有效的。他們非常有效的原因是因?yàn)長STM能夠存儲(chǔ)過去重要的信息,并忘記不重要的信息。LSTM有三個(gè)門:
現(xiàn)在,讓我們將LSTM實(shí)現(xiàn)為一個(gè)黑盒子,并檢查它在我們的特定數(shù)據(jù)上的性能。 Python代碼導(dǎo)入所需要的庫from sklearn.preprocessing import MinMaxScaler 創(chuàng)建dataframedata = df.sort_index(ascending=True, axis=0) 設(shè)置索引new_data.index = new_data.Date 創(chuàng)建訓(xùn)練集和測(cè)試集dataset = new_data.values train = dataset[0:987,:] 將數(shù)據(jù)集轉(zhuǎn)換為X列和Y列scaler = MinMaxScaler(feature_range=(0, 1)) x_train, y_train = [], [] x_train = np.reshape(x_train, (x_train.shape[0],x_train.shape[1],1)) 創(chuàng)建并使用LSTM網(wǎng)絡(luò)model = Sequential() model.compile(loss='mean_squared_error', optimizer='adam') 使用訓(xùn)練集中的過去的60個(gè)值預(yù)測(cè)246個(gè)值inputs = new_data[len(new_data) - len(valid) - 60:].values X_test = [] X_test = np.reshape(X_test, (X_test.shape[0],X_test.shape[1],1)) 結(jié)果rms=np.sqrt(np.mean(np.power((valid-closing_price),2))) 11.772259608962642 畫圖train = new_data[:987] 推論LSTM模型可以根據(jù)不同的參數(shù)進(jìn)行調(diào)整,例如改變LSTM層的數(shù)量,添加dropout值或增加epoch的數(shù)量。但LSTM的預(yù)測(cè)是否足以確定股價(jià)是漲還是降?當(dāng)然不是! 正如我在文章開頭提到的那樣,股票價(jià)格受到有關(guān)公司的新聞以及其他因素的影響,如公司的非貨幣化或合并/分拆。還有一些無形因素,往往是事先無法預(yù)測(cè)的。 結(jié)束筆記時(shí)間序列預(yù)測(cè)是一個(gè)非常有趣的領(lǐng)域,正如我在撰寫這些文章時(shí)所認(rèn)識(shí)到的那樣。在社區(qū)中有一種看法,認(rèn)為它是一個(gè)非常復(fù)雜的領(lǐng)域,雖然有些的確比較復(fù)雜,但是一旦掌握了基本技術(shù),也就不那么困難了。 本文作者使用了六種方法來進(jìn)行了對(duì)股票漲跌的預(yù)測(cè),并從結(jié)果中分析了每個(gè)算法用于時(shí)間序列模型的優(yōu)劣,并且從圖中可以看出LSTM方法是擬合最好的一種方法,但是股票市場(chǎng)需要考慮的因素有很多,并不是只需要幾個(gè)關(guān)鍵的特征就可以預(yù)測(cè)的,我們可以根據(jù)以前的數(shù)據(jù),對(duì)算法進(jìn)行驗(yàn)證,但使用算法去預(yù)測(cè)未來的股票的漲跌,還是有一些風(fēng)險(xiǎn)的,所以還是要謹(jǐn)慎的去使用這些算法。至少現(xiàn)在沒有一種算法可以百分之百的去預(yù)測(cè)未來股票的時(shí)間序列模型算法,還是先暫時(shí)的用算法去不斷的訓(xùn)練,直到未來技術(shù)成熟的一天。 Stock Prices Prediction Using Machine Learning and Deep Learning Techniques (with Python codes) |
|