Python 與金融科技8|生成機器學習的預處理資料
技術標籤:Python金融資料大資料python機器學習人工智慧
接下來幾期我們將使用機器學習方法幫助我們預測未來股票交易資料的走勢。在此之前我們需要對資料進行預處理以供機器學習方法使用。這一期我們將以復權收盤價資料為例,學習如何生成有效的特徵資料。
前言
在這個系列中,我們將共同學習如何藉助Python這個強大的工具處理金融資料。在正式開始這個系列的學習之前,需要您具有Python程式設計的基礎知識,至少需要將Python安裝好。如果暫時還不滿足這一要求的,建議先關注公眾號 IT資訊教室,學習 Python入門教程。
內容首發於微信公眾號IT資訊教室,如果您想學習更多AI相關的技能,歡迎搜尋關注或微信掃描下方二維碼關注~~
概 述
前面幾期的教程中,我們學習了從網上獲取交易資料的方法,學習了將資料視覺化的方法,學習了簡單的資料清洗和資料合併的方法,另外,我們還學習了分析資料之間的相關性以及將相關性關係以視覺化的方式展現出來。
接下來,我們將進一步處理這些資料,並基於這些資料,藉助機器學習的一些方法幫助我們更深入的分析和預測現有以及未來的資料。
同樣以這裡的股票資料為例,我們知道,隨著時間的推移,資料之間可能存在一些相關性。例如,一個公司的股票走勢,可能會受到其他相關公司的股票走勢的影響,那麼如果能夠讓計算機找到並且模擬這一相關性的關係,從某種程度上來說,我們就可以預測特定公司未來的交易資訊。
這一目標可以通過‘機器學習’來實現。機器學習的過程實際上是去建立資料的特徵與標籤的對映關係,並把所有的標籤分類。有了這樣一種關係之後,給定一個特徵,‘機器’ 就會將特徵對映為一個‘標籤’,這個標籤所屬的類別就可以作為預測的結果。
對於股票資料來說,特徵可以是股票的價格。一般的,為了讓預測結果更加準確,需要選取一些有代表性的特徵。
我們選取未來幾天內每一支股票價格的變化率作為特徵,將股票的變化趨勢作為標籤,我們將一部分標籤分為繼續買入一類,一部分作為賣出類,其餘部分作為繼續持有類。
例如我們可以規定,對於股票 A,如果在接下來的 x 天內,股票成交價的增幅可能在 y% 以上,我們就在當前時間點繼續買入這家股票。如果未來 x 天成交價的降幅在 y% 以上,我們就在當前時間點賣出這家股票。對於其他預測結果,我們選擇繼續持有這家股票。
所以,我們的目標是使用機器學習方法,預測未來 x 天的交易資訊,並給出指導性的交易方案(買入/賣出/繼續持有)。
資料特徵的生成
我們首先生成交易資訊的特徵資料,按照前面的分析,在當前時間點,我們選取最多 x 天后股價相對於當前時間點股票變化的百分比作為特徵。
例如取 x=7,那麼對於股票 A,我們就建立 7 列特徵資料,分別表示 1 天后,2 天后,…,7 天后的股價相比於當前股價的變化率。我們使用函式 processDataForLables 來實現這一功能:
def processDataForLables(ticker):
函式的引數是股票程式碼,我們需要為每一支想要分析的股票建立特徵資料。
這一期我們主要還是以每支股票的復權收盤價為例,與往常一樣,首先讀取交易資料:
dataFrame = pd.read_csv('SS50JoinedClose.csv', index_col=0)
然後對資料進行簡單的過濾清洗,將空白資料都用 0 填充:
dataFrame.fillna(0, inplace=True)
另外,為了方便後續的一些操作,先提取所有的股票程式碼,以列表的格式儲存在變數 tickers 中備用:
tickers = dataFrame.columns.values
接下來,設定資料的特徵:
nDays = 7
for i in range(1, nDays+1):
dataFrame['{}_{}d'.format(ticker, i)] = (dataFrame[ticker].shift(-i) - dataFrame[ticker]) / dataFrame[ticker]
我們使用 shift(-i) 這個方法獲取 i 天后的收盤價。這裡生成了 7 天內的特徵值,對於名稱為 ticker 的股票,生成 7 列特徵值,每一列的索引名稱為 ‘ticker_1d’, ‘ticker_2d’, … , ‘ticker_7d’。
接下來,再對生成的資料進行簡單的處理,同樣的方法,將空白的位置填充上 0:
dataFrame.fillna(0, inplace=True)
這樣對於任意給定的股票,就生成了它的特徵資訊,最後函式範圍生成的特徵值,為了後續方便使用,我們同時返回所有的股票程式碼:
return tickers, dataFrame
最後測試一下,以 ‘600585.SS’ 這支股票為例:
tickers, dataFrame = processDataForLables('600585.SS')
print(dataFrame)
參考輸出如下
600036.SS 601229.SS ... 600585.SS_6d 600585.SS_7d
Date ...
2010-01-04 11.171289 0.00 ... -0.050209 -0.090043
2010-01-05 11.183971 0.00 ... -0.078956 -0.072449
2010-01-06 10.950527 0.00 ... -0.074588 -0.078360
2010-01-07 10.666690 0.00 ... -0.048042 -0.045659
2010-01-08 10.666690 0.00 ... -0.047514 -0.011015
... ... ... ... ...
2020-11-23 45.400002 7.98 ... 0.000000 0.000000
2020-11-24 44.869999 7.94 ... 0.000000 0.000000
2020-11-25 44.430000 7.93 ... 0.000000 0.000000
2020-11-26 45.090000 7.96 ... 0.000000 0.000000
2020-11-27 45.849998 8.09 ... 0.000000 0.000000
[2649 rows x 57 columns]
參考程式碼
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: IT資訊教室(微信公眾號)
訂閱/關注,在看、分享三連吧~
"""
def processDataForLables(ticker):
dataFrame = pd.read_csv('SS50JoinedClose.csv', index_col=0)
dataFrame.fillna(0, inplace=True)
tickers = dataFrame.columns.values
nDays = 7
for i in range(1, nDays+1):
# The increasing rate of adj close with i day(s).
dataFrame['{}_{}d'.format(ticker, i)] = (dataFrame[ticker].shift(-i) - dataFrame[ticker]) / dataFrame[ticker]
dataFrame.fillna(0, inplace=True)
return tickers, dataFrame
tickers, dataFrame = processDataForLables('600585.SS')
print(dataFrame)