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 總結和版權說明
本文是給程序員加財商系列,之前還有兩篇博文
有不少網友轉載和想要轉載我的博文,本人感到十分榮幸,這也是本人不斷寫博文的動力。關於本文的版權有如下統一的說明,抱歉就不逐一回復了。
1 本文可轉載,無需告知,轉載時請用鏈接的方式,給出原文出處,別簡單地通過文本方式給出,同時寫明原作者是hsm_computer。
2 在轉載時,請原文轉載 ,謝絕洗稿。否則本人保留追究法律責任的權利。