機器學習:使用scikit-learn的線性回歸預測Google股票


這是機器學習系列的第一篇文章。

本文將使用Pythonscikit-learn的線性回歸預測Google的股票走勢。請千萬別期望這個示例能夠讓你成為股票高手。下面按逐步介紹如何進行實踐。

准備數據

本文使用的數據來自www.quandl.com網站。使用Python相應的quandl庫就可以通過簡單的幾行代碼獲取到我們想要的數據。本文使用的是其中的免費數據。利用下面代碼就可以拿到數據:

import quandl
df = quandl.get('WIKI/GOOGL')

其中WIKI/GOOGL是數據集的ID,可以在網站查詢到。不過我發現新版本的Quandl要求用戶在其網站注冊獲取身份信息,然后利用身份信息才能讀取數據。這里用到的WIKI/GOOGL數據集屬於舊版本接口提供的數據,不需要提供身份信息。

通過上面代碼,我們把數據獲取到,並存放在df變量中。默認地,Quandl獲取到的數據以PandasDataFrame存儲。因此你可以通過DataFrame的相關函數查看數據內容。如下圖,使用print(df.head())可以打印表格數據的頭幾行內容。

 

預處理數據

從上面圖片我們看到數據集提供了很多列字段,例如Open記錄了股票開盤價、Close記錄了收盤價、Volumn記錄了當天的成交量。帶Adj.前綴的數據應該是除權后的數據。

我們並不需要用到所有的字段,因為我們的目標是預測股票的走勢,因此需要研究的對象是某一時刻的股票價格,這樣的有比較性。所以我們以除權后的收盤價Adj. Close為研究對象來描述股票價格,也就是我們選擇它作為將要被預測的變量。

接下來需要考慮關於什么變量跟股票價格有關。下面代碼選取了幾個可能影響Adj. Close變化的字段作為回歸預測的特征,並對這些特征進行處理。詳細步驟請閱讀注釋。

import math
import numpy as np

# 定義預測列變量,它存放研究對象的標簽名
forecast_col = 'Adj. Close'
# 定義預測天數,這里設置為所有數據量長度的1%
forecast_out = int(math.ceil(0.01*len(df)))

# 只用到df中下面的幾個字段
df = df[['Adj. Open', 'Adj. High', 'Adj. Low', 'Adj. Close', 'Adj. Volume']]

# 構造兩個新的列
# HL_PCT為股票最高價與最低價的變化百分比
df['HL_PCT'] = (df['Adj. High'] - df['Adj. Close']) / df['Adj. Close'] * 100.0
# HL_PCT為股票收盤價與開盤價的變化百分比
df['PCT_change'] = (df['Adj. Close'] - df['Adj. Open']) / df['Adj. Open'] * 100.0

# 下面為真正用到的特征字段
df = df[['Adj. Close', 'HL_PCT', 'PCT_change', 'Adj. Volume']]
# 因為scikit-learn並不會處理空數據,需要把為空的數據都設置為一個比較難出現的值,這里取-9999,
df.fillna(-99999, inplace=True)
# 用label代表該字段,是預測結果
# 通過讓與Adj. Close列的數據往前移動1%行來表示
df['label'] = df[forecast_col].shift(-forecast_out)

# 最后生成真正在模型中使用的數據X和y和預測時用到的數據數據X_lately
X = np.array(df.drop(['label'], 1))
# TODO 此處尚有疑問
X = preprocessing.scale(X)
# 上面生成label列時留下的最后1%行的數據,這些行並沒有label數據,因此我們可以拿他們作為預測時用到的輸入數據
X_lately = X[-forecast_out:]
X = X[:-forecast_out]
# 拋棄label列中為空的那些行
df.dropna(inplace=True)
y = np.array(df['label'])

上面代碼難點在理解label列的是如何生成的以及有什么用。實際上這一列的第i個元素都是Adj. Close列的第i + forecast_out個元素。我想嘗試用簡單文字描述:這列的每個數據是真實統計中的未來forecast_out天的收盤價。利用這一列的數據作為線性回歸模型的監督標准,讓模型學習出規律,然后我們才能用之預測結果。

另外X = preprocessing.scale(X)這行代碼對X的數據進行規范化處理,讓X的數據服從正態分布。(PS. 但是,我發現這種處理讓X的數據都發生了變化,因此無法理解這樣做的原因,以及為什么不會影響模型學習的結果。有知道答案的麻煩留言告告知。)

線性回歸

上面我們已經准備好了數據。可以開始構建線性回歸模型,並讓用數據訓練它。

# scikit-learn從0.2版本開始廢棄cross_validation,改用model_selection
from sklearn import preprocessing, model_selection, svm
from sklearn.linear_model import LinearRegression

# 開始前,先X和y把數據分成兩部分,一部分用來訓練,一部分用來測試
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=0.2)

# 生成scikit-learn的線性回歸對象
clf = LinearRegression(n_jobs=-1)
# 開始訓練
clf.fit(X_train, y_train)
# 用測試數據評估准確性
accuracy = clf.score(X_test, y_test) 
# 進行預測
forecast_set = clf.predict(X_lately)

print(forecast_set, accuracy)

上述幾行代碼就是使用scikit-learn進行線性回歸的訓練和預測過程。我們可以通過測試數據計算模型的准確性accuracy,並且通過向模型提供X_lately計算預測結果forecast_set

我運行得到的結果如下:

 
 

需要注意到的這個准確性accuracy並不表示模型預測100天的數據有97天是正確的。它表示的是線性模型能夠描述統計數據的信息的一個統計概念。在后續的文章我可能會對這個變量進行一些討論。

繪制走勢

最后我們使用matplotlib讓數據可視化話。詳細步驟看代碼注釋。

import matplotlib.pyplot as plt
from matplotlib import style
import datetime

# 修改matplotlib樣式
style.use('ggplot')

one_day = 86400
# 在df中新建Forecast列,用於存放預測結果的數據
df['Forecast'] = np.nan
# 取df最后一行的時間索引
last_date = df.iloc[-1].name
last_unix = last_date.timestamp()
next_unix = last_unix + one_day

# 遍歷預測結果,用它往df追加行
# 這些行除了Forecast字段,其他都設為np.nan
for i in forecast_set:
    next_date = datetime.datetime.fromtimestamp(next_unix)
    next_unix += one_day
    # [np.nan for _ in range(len(df.columns) - 1)]生成不包含Forecast字段的列表
    # 而[i]是只包含Forecast值的列表
    # 上述兩個列表拼接在一起就組成了新行,按日期追加到df的下面
    df.loc[next_date] = [np.nan for _ in range(len(df.columns) - 1)] + [i]

# 開始繪圖
df['Adj. Close'].plot()
df['Forecast'].plot()
plt.legend(loc=4)
plt.xlabel('Date')
plt.ylabel('Price')
plt.show()

運行代碼可以得到下圖。

 

上圖紅色部分為采集到的已有數據,藍色部分為預測數據。

點擊這里查看完整代碼

本文來自同步博客


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM