前陣子報名參加了一個數據比賽,題目是預測5月15號(星期三)招商銀行的股價,截止時間是在5月12號(星期天)。在本次預測中,我用到的是嶺迴歸。python
先回顧一下普通線性迴歸。通常來講,線性迴歸方程:y=w1x1+w2x2...+wnxn。咱們把這組變量 xn 定成一個矩陣 X,把迴歸係數存放在向量W中,則 y=X*W。算法
當特徵數大於樣本數的時候,上面的式子就存在問題了。矩陣要求逆,就必須爲滿秩矩陣,當特徵數大於樣本數的時候,就不爲滿秩了。能夠通俗地理解爲因爲樣本數量太少,沒有辦法提供足夠的有效的信息。app
多重共線性指線性迴歸模型中的解釋變量之間因爲存在精確相關關係或高度相關關係而使模型估計失真或難以估計準確。舉個例子,對於通常人來講,體重和身高是有很強的關聯的,但若是咱們須要預測某樣東西,以這二者做爲自變量,即便能夠很好的擬合,但這個模型的解釋性仍是不夠。函數
因爲上面兩個問題的存在,嶺迴歸就出現了。它解決迴歸中重大疑難問題:排除多重共線性,進行變量的選擇,在存在共線性問題和病態數據偏多的研究中有較大的實用價值。按照度孃的解釋:嶺迴歸是一種專用於共線性數據分析的有偏估計迴歸方法,實質上是一種改良的最小二乘估計法,經過放棄最小二乘法的無偏性,以損失部分信息、下降精度爲代價得到迴歸係數更爲符合實際、更可靠的迴歸方法,對病態數據的擬合要強於最小二乘法。測試
嶺迴歸在上面式子的基礎上作了點兒改進:,(其中
稱爲嶺參數)很好地解決了上面的問題,假如
是一個奇異矩陣(不滿秩),添加
後能夠保證其可逆。spa
本次數據是經過 Tushare 的 get_hist_data()獲取的。Tushare是一個免費、開源的python財經數據接口包。python安裝tushare直接經過
pip install tushare 便可安裝。code
import tushare as ts data = ts.get_hist_data('600848')
運行以後能夠查看它的先後幾行數據,按照tushare官方的說明,get_hist_data()只能獲取近3年的日線數據,而他的返回值的說明是這樣的:
〖date:日期;open:開盤價;high:最高價;close:收盤價;low:最低價;volume:成交量;price_change:價格變更;p_change:漲跌幅;ma5:5日均價;ma10:10日均價;ma20:20日均價;v_ma5:5日均量;v_ma10:10日均量;v_ma20:20日均量〗xml
均價的意思大概就是股票n天的成交價格或指數的平均值。均量則跟成交量有關。至於其餘的返回值,應該是一會兒就能明白的吧。在得到數據以後,咱們查看一下描述性統計,經過 data.describe()
查看是否存在什麼異常值或者缺失值。blog
這樣看來彷佛除了因爲週末以及節假日不開盤致使的當天的數據缺失之外,並無其餘的缺失和異常。可是這裏咱們不考慮節假日的缺失值。排序
因爲獲取的數據是按日期降序排序,但本次預測跟時間序列有關,所以咱們須要把順序轉一下,讓它按照日期升序排序。
data1 = data[::-1]
處理完順序以後,咱們要作一下特徵值的選擇。因爲 volume 以及均量的值很大,若是不進行處理的話,極可能對總體的預測形成不良影響。因爲時間有限,並且考慮到運算的複雜度,這裏我沒有對這些特徵進行處理,而是直接將它們去掉了。至於均價,我是按照本身的理解,和10日均價、20日均價相比,5日均價的範圍沒那麼大,對近期的預測會比另外兩個要好,所以保留5日均價。接着,我用 sklearn.model_selection 的 cross_val_score,分別查看除〖'open', 'close', 'high', 'low', 'ma5'〗之外的其餘剩餘屬性對預測值的影響。發現 ‘p_change’、'price_change' 這兩個屬性對預測結果的影響不大,爲了節省內存,增長運算速度,提升預測的準確性,也直接把它們去掉了。完了以後,查看先後三行數據。
data1 = data1[['open','high','low','ma5','close']] data1.head(3), data1.tail(3)
因爲提交截止日期是週日,預測的是週三,所以須要先對週一週二的信息進行預測。在這裏我忽然想到一個問題,是用前一天的全部數據來訓練模型以預測當天的 close 比較準確,仍是用當天除了 close 之外的其餘數據來訓練模型以訓練當天的 close 比較準呢?爲了驗證這個問題,我分別對這兩種方法作了實驗。
爲了減小代碼量,定義了一個函數用以評估模型的錯誤率。
def get_score(X_train, y_train): ridge_score = np.sqrt(-cross_val_score(ridge, X_train, y_train, cv=10, scoring='neg_mean_squared_error')) return np.mean(ridge_score)
(1)、用前一天的全部數據來當訓練集
y_train = data1['close'].values[1:] X_train = data1.values[:-1] score = get_score(X_train, y_train)
輸出結果大約爲0.469,這個錯誤率就比較大了,不太合理,更況且還要預測其餘特徵值做爲測試數據。
(2)、用當天除了 close 之外的其餘數據來當訓練集
data2 = data1[:] y_train = data2.pop('close').values X_train = data2.values score = get_score(X_train, y_train)
輸出結果大約爲0.183,跟第一個相比簡直好多了。因此,就決定是你了!
接下來建模並把模型保存下來:
y_train = data1['close'] X_train = data1[['open', 'high', 'low', 'ma5']] close_model = ridge.fit(X_train, y_train) joblib.dump(ridge, 'close_model.m')
在預測以前呢,咱們先拿訓練集的後8組數據作一下測試,作個圖看看:
scores = [] for x in X_train[-8:]: score = close_model.predict(np.array(x).reshape(1, -1)) scores.append(score) x = np.arange(8) fig, axes = plt.subplots(1, 1, figsize=(13, 6)) axes.plot(scores) axes.plot(y_train[-8:]) plt.xticks(x, data1.index[-8:].values, size=13, rotation=0)
看到這樣子我仍是相對比較放心的,不過,這個模型的訓練值除了「close」之外的屬性都是已知的,要預測三天後的還得預測前兩天的測試值。
def get_model(s): y_train = data1[s].values[1:] X_train = data1.values[:-1] model = ridge.fit(X_train, y_train) return model
def get_results(X_test): attrs = ['open', 'high', 'low', 'ma5'] results = [] for attr in attrs: result = get_model(attr).predict(X_test) results.append(result) return results
接下來預測三天的股價:
X_test = data1[-1:].values for i in range(3): results = get_results(X_test) close = close_model.predict(np.array(results).reshape(1, -1)) results.append(close) X_test = np.array(results).reshape(1, -1) print("5月15日招商銀行關盤時的股價爲:" + str(round(close[0], 2)))
5月15日招商銀行關盤時的股價爲:33.44
雖然預測結果是這樣子,但感受這樣預測彷佛很菜啊。畢竟預測的每一個值都會有誤差,多個誤差累加起來就不少了,這讓我有點懼怕。不知道存不存在不預測其餘值直接預測close的方法,或者說直接預測5月15號的而不用先預測1三、14號的方法。雖然我知道有種算法是時間序列算法,但不是很懂。但願哪位大神看了能給我一些建議,指點迷津。
對於一個自學數據分析的在校學生,苦於沒有項目經驗,正好遇上此次的【數據遊戲】,能利用這次機會操做一波真的很不錯。