1. 程式人生 > >以預測股票漲跌案例入門基於SVM的機器學習

以預測股票漲跌案例入門基於SVM的機器學習

    SVM是Support Vector Machine的縮寫,中文叫支援向量機,通過它可以對樣本資料進行分類。以股票為例,SVM能根據若干特徵樣本資料,把待預測的目標結果劃分成“漲”和”跌”兩種,從而實現預測股票漲跌的效果。

1 通過簡單案例瞭解SVM的分類作用

    在Sklearn庫裡,封裝了SVM分類的相關方法,也就是說,我們無需瞭解其中複雜的演算法,即可用它實現基於SVM的分類。通過如下SimpleSVMDemo.py案例,我們來看下通過SVM庫實現分類的做法,以及相關方法的呼叫方式。    

1    #!/usr/bin/env python
2    #coding=utf-8
3    import numpy as np
4    import matplotlib.pyplot as plt
5    from sklearn import svm
6    #給出平面上的若干點
7    points = np.r_[[[-1,1],[1.5,1.5],[1.8,0.2],[0.8,0.7],[2.2,2.8],[2.5,3.5],[4,2]]]
8    #按0和1標記成兩類
9    typeName = [0,0,0,0,1,1,1]

    在第5行裡,我們引入了基於SVM的庫。在第7行,我們定義了若干個點,並在第9行把這些點分成了兩類,比如[-1,1]點是第一類,而[4,2]是第二類。

    這裡請注意,在第7行定義點的時候,是通過np.r_方法,把資料轉換成“列矩陣”,這樣做的目的是讓資料結構滿足fit方法的要求。     

10	#建立模型
11	svmTool = svm.SVC(kernel='linear')
12	svmTool.fit(points,typeName)  #傳入引數
13	#確立分類的直線
14	sample = svmTool.coef_[0] #係數
15	slope = -sample[0]/sample[1]  #斜率
16	lineX = np.arange(-2,5,1)#獲取-2到5,間距是1的若干資料
17	lineY = slope*lineX-(svmTool.intercept_[0])/sample[1]

  在第11行裡,我們建立了基於SVM的物件,並指定該SVM模型採用比較常用的“線性核”來實現分類操作。

      在第14行,通過fit訓練樣本。這裡fit方法和之前基於線性迴歸案例中的fit方法是一樣的,只不過這裡是基於線性核的相關演算法,而之前是基於線性迴歸的相關演算法(比如最小二乘法)。訓練完成後,通過第14行和第15行的程式碼,我們得到了能分隔兩類樣本的直線,包括直線的斜率和截距,並通過第16行和第17行的程式碼設定了分隔線的若干個點。    

18	#畫出劃分直線
19	plt.plot(lineX,lineY,color='blue',label='Classified Line')
20	plt.legend(loc='best') #繪製圖例
21	plt.scatter(points[:,0],points[:,1],c='R')
22	plt.show()

  計算完成後,我們通過第19行的plot方法繪製了分隔線,並在第21行通過scatter方法繪製所有的樣本點。由於points是“列矩陣”的資料結構,所以是用points[:,0]來獲取繪製點的 x座標,用points[:,1]來獲取y座標,最後是通過第22行的show方法繪製圖形。執行上述程式碼,我們能看到如下圖13.8的效果,從中我們能看到,藍色的邊界線能有效地分隔兩類樣本。

    

    從這個例子中我們能看到,SVM的作用是,根據樣本,訓練出能劃分不同種類資料的邊界線,由此實現“分類”的效果。而且,在根據訓練樣本確定好邊界線的引數後,還能根據其它沒有明確種類樣本,計算出它的種類,以此實現“預測”效果。 

2 資料標準化處理

    標準化(normalization)處理是將特徵樣本按一定演算法進行縮放,讓它們落在某個範圍比較小的區間,同時去掉單位限制,讓樣本資料轉換成無量綱的純數值。

    在用機器學習方法進行訓練時,一般需要進行標準化處理,原因是Sklearn等庫封裝的一些機器學習演算法對樣本有一定的要求,如果有些特徵值的數量級偏離大多數特徵值的數量級,或者有特徵值偏離正態分佈,那麼預測結果會不準確。

    需要說明的是,雖然在訓練前對樣本進行了標準化處理,改變了樣本值,但由於在標準化的過程中是用同一個演算法對全部樣本進行轉換,屬於“資料優化”,不會對後繼的訓練起到不好的作用。

    這裡我們是通過sklearn庫提供的preprocessing.scale方法實現標準化,該方法是讓特徵值減去平均值然後除以標準差。通過如下ScaleDemo.py案例,我們實際用下preprocessing.scale方法。     

1	#!/usr/bin/env python
2	#coding=utf-8
3	from sklearn import preprocessing
4	import numpy as np
5	
6	origVal = np.array([[10,5,3],
7	                   [8,6,12],
8	                   [14,7,15]])
9	#計算均值
10	avgOrig = origVal.mean(axis=0)
11	#計算標準差
12	stdOrig=origVal.std(axis=0)
13	#減去均值,除以標準差
14	print((origVal-avgOrig)/stdOrig)
15	scaledVal=preprocessing.scale(origVal)
16	#直接輸出preprocessing.scale後的結果
17	print(scaledVal)

  在第6行裡,我們初始化了一個長寬各為3的矩陣,在第10行,通過mean方法計算了該矩陣的均值,在第12行則通過std方法計算標準差。

      第14行是用原始值減去均值,再除以標準差,在第17行,是直接輸出preprocessing.scale的結果。第14行和第17行的輸出結果相同,均是下值,從中我們驗證了標準化的具體做法。    

1	[[-0.26726124 -1.22474487 -1.37281295]
2	 [-1.06904497  0.          0.39223227]
3	 [ 1.33630621  1.22474487  0.98058068]]

   

3 預測股票漲跌

    在之前的案例中,我們用基於SVM的方法,通過一維直線來分類二維的點。據此可以進一步推論:通過基於SVM的方法,我們還可以分類具有多個特徵值的樣本。

    比如可以通過開盤價、收盤價、最高價、最低價和成交量等特徵值,用SVM的演算法訓練出這些特徵值和股票“漲“和“跌“的關係,即通過特徵值劃分指定股票“漲”和“跌”的邊界,這樣的話,一旦輸入其它的股票特徵資料,即可預測出對應的漲跌情況。在如下的PredictStockBySVM.py案例中,我們給出了基於SVM預測股票漲跌的功能。     

1	#!/usr/bin/env python
2	#coding=utf-8
3	import pandas as pd 
4	from sklearn import svm,preprocessing
5	import matplotlib.pyplot as plt
6	origDf=pd.read_csv('D:/stockData/ch13/6035052018-09-012019-05-31.csv',encoding='gbk')
7	df=origDf[['Close', 'Low','Open' ,'Vol','Date']]
8	#diff列表示本日和上日收盤價的差
9	df['diff'] = df["Close"]-df["Close"].shift(1)
10	df['diff'].fillna(0, inplace = True)
11	#up列表示本日是否上漲,1表示漲,0表示跌
12	df['up'] = df['diff']   
13	df['up'][df['diff']>0] = 1
14	df['up'][df['diff']<=0] = 0
15	#預測值暫且初始化為0
16	df['predictForUp'] = 0

  第6行裡,我們從指定檔案讀取了包含股票資訊的csv檔案,該csv格式的檔案其實是從網路資料介面獲取得到的,具體做法可以參考前面博文。

    從第9行裡,我們設定了df的diff列為本日收盤價和前日收盤價的差值,通過第12行到第14行的程式碼,我們設定了up列的值,具體是,如果當日股票上漲,即本日收盤價大於前日收盤價,則up值是1,反之如果當日股票下跌,up值則為0。

    在第16行裡,我們在df物件裡新建了表示預測結果的predictForUp列,該列的值暫且都設定為0,在後繼的程式碼裡,將根據預測結果填充這列的值。    

17	#目標值是真實的漲跌情況
18	target = df['up']
19	length=len(df)
20	trainNum=int(length*0.8)
21	predictNum=length-trainNum
22	#選擇指定列作為特徵列
23	feature=df[['Close', 'High', 'Low','Open' ,'Volume']]
24	#標準化處理特徵值
25	feature=preprocessing.scale(feature)

  在第18行裡,我們設定訓練目標值是表示漲跌情況的up列,在第20行,設定了訓練集的數量是總量的80%,在第23行則設定了訓練的特徵值,請注意這裡去掉了日期這個不相關的列,而且,在第25行,對特徵值進行了標準化處理。    

26	#訓練集的特徵值和目標值
27	featureTrain=feature[1:trainNum-1]
28	targetTrain=target[1:trainNum-1]
29	svmTool = svm.SVC(kernel='liner')
30	svmTool.fit(featureTrain,targetTrain)

  在第27行和第28行裡,我們通過擷取指定行的方式,得到了特徵值和目標值的訓練集,在第26行裡,以線性核的方式建立了SVM分類器物件svmTool。

     在第30行裡,通過fit方法,用特徵值和目標值的訓練集訓練svmTool分類物件。從上文裡我們已經看到,訓練所用的特徵值是開盤收盤價、最高最低價和成交量,訓練所用的目標值是描述漲跌情況的up列。在訓練完成後,svmTool物件中就包含了能劃分股票漲跌的相關引數。

31	predictedIndex=trainNum
32	#逐行預測測試集
33	while predictedIndex<length:
34	    testFeature=feature[predictedIndex:predictedIndex+1]            
35	    predictForUp=svmTool.predict(testFeature)    
36	    df.ix[predictedIndex,'predictForUp']=predictForUp    
37	    predictedIndex = predictedIndex+1

    在第33行的while迴圈裡,我們通過predictedIndex索引值,依次遍歷測試集。

    在遍歷過程中,通過第35行的predict方法,用訓練好的svmTool分類器,逐行預測測試集中的股票漲跌情況,並在第36行裡,把預測結果設定到df物件的predictForUp列中。      

38	#該物件只包含預測資料,即只包含測試集
39	dfWithPredicted = df[trainNum:length]
40	#開始繪圖,建立兩個子圖
41	figure = plt.figure()
42	#建立子圖     
43	(axClose, axUpOrDown) = figure.subplots(2, sharex=True)
44	dfWithPredicted['Close'].plot(ax=axClose)
45	dfWithPredicted['predictForUp'].plot(ax=axUpOrDown,color="red", label='Predicted Data')
46	dfWithPredicted['up'].plot(ax=axUpOrDown,color="blue",label='Real Data')
47	plt.legend(loc='best') #繪製圖例
48	#設定x軸座標標籤和旋轉角度
49	major_index=dfWithPredicted.index[dfWithPredicted.index%2==0]
50	major_xtics=dfWithPredicted['Date'][dfWithPredicted.index%2==0]
51	plt.xticks(major_index,major_xtics)
52	plt.setp(plt.gca().get_xticklabels(), rotation=30) 
53	plt.title("通過SVM預測603505的漲跌情況")
54	plt.rcParams['font.sans-serif']=['SimHei']
55	plt.show()

  由於在之前的程式碼裡,我們只設置測試集的predictForUp列,並沒有設定訓練集的該列資料,所以在第39行裡,用切片的手段,把測試集資料放置到dfWithPredicted物件中,請注意這裡切片的起始和結束值是測試集的起始和結束索引值。至此完成了資料準備工作,在之後的程式碼裡,我們將用matplotlib庫開始繪圖。

    在第43行裡,我們通過subplots方法設定了兩個子圖,並通過sharex=True讓這兩個子圖的x軸具有相同的刻度和標籤。在第44行程式碼裡,在axClose子圖中,我們用plot方法繪製了收盤價的走勢。在第45行程式碼裡,在axUpOrDown子圖中,我們繪製了預測到的漲跌情況,而在第46行裡,還是在axUpOrDown子圖裡,繪製了這些天的股票真實的漲跌情況。

    在第49行到第52行的程式碼裡,我們設定了x標籤的文字以及旋轉角度,這樣做的目的是讓標籤文字看上去不至於太密集。在第53行裡,我們設定了中文標題,由於要顯示中文,所以需要第54行的程式碼,最後在55行通過show方法展示了圖片。執行上述程式碼,能看到如下圖所示的效果。

    

    其中上圖展示了收盤價,下圖的藍色線條表示真實的漲跌情況,0表示跌,1表示上漲,而紅色則表示預測後的結果。

4 結論

     對比一下,雖有偏差,但大體相符。綜上所述,本案例是數學角度,演示了通過SVM分類的做法,包括如果劃分特徵值和目標值,如何對樣本資料進行標準化處理,如何用訓練資料訓練SVM,還有如何用訓練後的結果預測分類結果。 

5 總結和版權說明

    本文是給程式設計師加財商系列,之前還有兩篇博文

  用python的matplotlib和numpy庫繪製股票K線均線和成交量的整合效果(含量化驗證交易策略程式碼)   用python的matplotlib和numpy庫繪製股票K線均線的整合效果(含從網路介面爬取資料和驗證交易策略程式碼)            本文的內容即將出書,在出版的書裡,是用股票案例和大家講述Python入門時的知識點,敬請期待     

    有不少網友轉載和想要轉載我的博文,本人感到十分榮幸,這也是本人不斷寫博文的動力。關於本文的版權有如下統一的說明,抱歉就不逐一回復了。

    1 本文可轉載,無需告知,轉載時請用連結的方式,給出原文出處,別簡單地通過文字方式給出,同時寫明原作者是hsm_computer。

    2 在轉載時,請原文轉載 ,謝絕洗稿。否則本人保留追究法律責任的權利。

 

&n