100天搞定機器學習|Day16 經過內核技巧實現SVM

前情回顧html

機器學習100天|Day1數據預處理
100天搞定機器學習|Day2簡單線性迴歸分析
100天搞定機器學習|Day3多元線性迴歸
100天搞定機器學習|Day4-6 邏輯迴歸
100天搞定機器學習|Day7 K-NN
100天搞定機器學習|Day8 邏輯迴歸的數學原理
100天搞定機器學習|Day9-12 支持向量機
100天搞定機器學習|Day11 實現KNN
100天搞定機器學習|Day13-14 SVM的實現
100天搞定機器學習|Day15 樸素貝葉斯
100天搞定機器學習|Day16 經過內核技巧實現SVM
算法

先再談一下須要對svm算法須要熟悉到什麼程度,這裏引用七月在線創始人July的微博:緩存

SVM理解到了必定程度後,是的確能在腦海裏從頭到尾推導出相關公式的,最初分類函數,最大化分類間隔,max1/||w||,min1/2||w||^2,凸二次規劃,拉格朗日函數,轉化爲對偶問題,SMO算法,都爲尋找一個最優解,一個最優分類平面。一步步梳理下來,爲何這樣那樣,太多東西能夠追究,最後實現。多線程

sklearn.svmSklearn包含的經常使用算法裏介紹過經常使用的算法,scikit-learn中學習模式的調用,有很強的統一性,調用機器學習的方法都是一個道理,算法就是一個類,其中包含fit(),predict()等等許多方法,咱們只要輸入訓練樣本和標記,以及模型的一些可能的參數,天然就直接出分類的結果。app

總結起來就是8個字:導入-建模-訓練-預測dom

先看個小例子,而後再細解。機器學習

import numpy as np  
X = np.array([[-1, -1], [-2, -1], [1, 1], [2, 1]])  
y = np.array([1, 1, 2, 2])  
from sklearn.svm import NuSVC  
clf = NuSVC()  
clf.fit(X, y)   
print(clf.fit(X,y))
NuSVC(cache_size=200, class_weight=None, coef0=0.0,
   decision_function_shape='ovr', degree=3, gamma='auto', kernel='rbf',
   max_iter=-1, nu=0.5, probability=False, random_state=None,
   shrinking=True, tol=0.001, verbose=False)
print(clf.predict([[-0.8, -1]])) 複製代碼

[1]
函數

更多案例,你們能夠移步scikit-learn官網tornado

https://scikit-learn.org/stable/modules/svm.html#svm-classification學習

scikit-learn中SVM的算法庫分爲兩類,

一類是分類的算法庫,包括SVC, NuSVC,和LinearSVC 3個類。

另外一類是迴歸算法庫,包括SVR, NuSVR,和LinearSVR 3個類。

相關的類都包裹在sklearn.svm模塊之中。

對於SVC, NuSVC,和LinearSVC 3個分類的類,SVC和 NuSVC差很少,區別僅僅在於對損失的度量方式不一樣,而LinearSVC從名字就能夠看出,他是線性分類,也就是不支持各類低維到高維的核函數,僅僅支持線性核函數,對線性不可分的數據不能使用。

一樣的,對於SVR, NuSVR,和LinearSVR 3個迴歸的類, SVR和NuSVR差很少,區別也僅僅在於對損失的度量方式不一樣。LinearSVR是線性迴歸,只能使用線性核函數。

下面咱們只說看一下SVC詳細用法,NuSVC、LinearSVC建議你們看一下劉建平Pinard@cnblogs統計的表格

https://www.cnblogs.com/pinard/p/6117515.html

SVC函數一共有14個參數:

SVC參數解釋

(1)C: 目標函數的懲罰係數C,用來平衡分類間隔margin和錯分樣本的,default C = 1.0;(2)kernel:參數選擇有RBF, Linear, Poly, Sigmoid, 默認的是"RBF";(3)degree:if you choose 'Poly' in param 2, this is effective, degree決定了多項式的最高次冪;(4)gamma:核函數的係數('Poly', 'RBF' and 'Sigmoid'), 默認是gamma = 1 / n_features;(5)coef0:核函數中的獨立項,'RBF' and 'Poly'有效;(6)probablity: 可能性估計是否使用(true or false);(7)shrinking:是否進行啓發式;(8)tol(default = 1e - 3): svm結束標準的精度;(9)cache_size: 制定訓練所須要的內存(以MB爲單位);(10)class_weight: 每一個類所佔據的權重,不一樣的類設置不一樣的懲罰參數C, 缺省的話自適應;(11)verbose: 跟多線程有關;(12)maxiter: 最大迭代次數,default = 1, if maxiter = -1, no limited;(13)decisionfunctionshape :‘ovo’ 一對一, ‘ovr’ 多對多 or None 無, default=None(14)random_state :用於機率估計的數據重排時的僞隨機數生成器的種子。

核函數如何選取

1)線性核函數(Linear Kernel)表達式爲:K(x,z)=x∙z,就是普通的內積,LinearSVC 和 LinearSVR 只能使用它。

2) 多項式核函數(Polynomial Kernel)是線性不可分SVM經常使用的核函數之一,表達式爲:,其中,γ,r,d都須要本身調參定義,比較麻煩。

3)高斯核函數(Gaussian Kernel),在SVM中也稱爲徑向基核函數(Radial Basis Function,RBF),它是libsvm默認的核函數,固然也是scikit-learn默認的核函數。表達式爲:, 其中,γ大於0,須要本身調參定義。

4)Sigmoid核函數(Sigmoid Kernel)也是線性不可分SVM經常使用的核函數之一,表達式爲:, 其中,γ,r都須要本身調參定義。

更多案例,你們能夠移步scikit-learn官網

最經常使用的是核函數是Linear與RBF,須要注意的是對數據歸一化處理。

一、Linear:主要用於線性可分的情形。參數少,速度快,對於通常數據,分類效果已經很理想了。

二、RBF:主要用於線性不可分的情形。參數多,分類結果很是依賴於參數。

吳恩達也曾經給出過選擇核函數的方法:

一、若是Feature的數量很大,跟樣本數量差很少,這時候選用LR或者是Linear Kernel的SVM

二、 若是Feature的數量比較小,樣本數量通常,不算大也不算小,選用SVM+Gaussian Kernel

三、 若是Feature的數量比較小,而樣本數量不少,須要手工添加一些feature變成第一種狀況

Kernel Trick實現svm04主要思想及算法流程來自李航的《統計學習方法》和以前推薦的《理解SVM的三重境界》(文末有PDF)

#coding=utf-8
import time
import random
import numpy as np
import math
import copy
a=np.matrix([[1.2,3.1,3.1]])
#print a.astype(int)
#print a.A

class SVM:
      def __init__(self,data,kernel,maxIter,C,epsilon):
            self.trainData=data
            self.C=C  #懲罰因子
            self.kernel=kernel
            self.maxIter=maxIter
            self.epsilon=epsilon
            self.a=[0 for i in range(len(self.trainData))]
            self.w=[0 for i in range(len(self.trainData[0][0]))]
            self.eCache=[[0,0] for i in range(len(self.trainData))]
            self.b=0
            self.xL=[self.trainData[i][0] for i in range(len(self.trainData))]
            self.yL=[self.trainData[i][1] for i in range(len(self.trainData))]

      def train(self):
            #support_Vector=self.__SMO()
            self.__SMO()
            self.__update()

      def __kernel(self,A,B):
            #核函數 是對輸入的向量進行變形 從低維映射到高維度
            res=0
            if self.kernel=='Line':
                  res=self.__Tdot(A,B)
            elif self.kernel[0]=='Gauss':
                  K=0
                  for m in range(len(A)):
                       K+=(A[m]-B[m])**2 
                  res=math.exp(-0.5*K/(self.kernel[1]**2))
            return res


      def __Tdot(self,A,B):
            res=0
            for k in range(len(A)):
                  res+=A[k]*B[k]
            return res


      def __SMO(self):
            #SMO是基於 KKT 條件的迭代求解最優化問題算法
            #SMO是SVM的核心算法
            support_Vector=[]
            self.a=[0 for i in range(len(self.trainData))]
            pre_a=copy.deepcopy(self.a)
            for it in range(self.maxIter):
                  flag=1
                  for i in range(len(self.xL)):
                        #print self.a
                        #更新 self.a  使用 機器學習實戰的求解思路
                        #計算 j更新
                        diff=0
                        self.__update()
                        #選擇有最大偏差的j 丹麥理工大學的算法是 對j在數據集上循環, 隨機選取i 顯然效率不是很高
                        #機器學習實戰 硬幣書表述正常 代碼混亂且有錯誤 啓發式搜索
                        Ei=self.__calE(self.xL[i],self.yL[i])
                        j,Ej=self.__chooseJ(i,Ei)
                        #計算 L H
                        (L,H)=self.__calLH(pre_a,j,i)
                        #思路是先表示爲self.a[j] 的惟一變量的函數 再進行求導(一階導數=0 更新)
                        kij=self.__kernel(self.xL[i],self.xL[i])+self.__kernel(self.xL[j],self.xL[j])-2*self.__kernel(self.xL[i],self.xL[j])
                        #print kij,"aa"
                        if(kij==0):
                              continue
                        self.a[j] = pre_a[j] + float(1.0*self.yL[j]*(Ei-Ej))/kij
                        #下屆是L 也就是截距,小於0時爲0
                        #上屆是H 也就是最大值,大於H時爲H
                        self.a[j] = min(self.a[j], H)
                        self.a[j] = max(self.a[j], L)
                        #self.a[j] = min(self.a[j], H)
                        #print L,H
                        self.eCache[j]=[1,self.__calE(self.xL[j],self.yL[j])]
                        self.a[i] = pre_a[i]+self.yL[i]*self.yL[j]*(pre_a[j]-self.a[j])
                        self.eCache[i]=[1,self.__calE(self.xL[i],self.yL[i])]
                        diff=sum([abs(pre_a[m]-self.a[m]) for m in range(len(self.a))])
                        #print diff,pre_a,self.a
                        if diff < self.epsilon:
                              flag=0
                        pre_a=copy.deepcopy(self.a)
                  if flag==0:
                        print (it,"break")
                        break

            #return support_Vector

      def __chooseJ(self,i,Ei):
            self.eCache[i]=[1,Ei]
            chooseList=[]
            #print self.eCache
            #從偏差緩存中獲得備選的j的列表 chooseList  偏差緩存的做用:解決初始選擇問題
            for p in range(len(self.eCache)):
                  if self.eCache[p][0]!=0 and p!=i:
                        chooseList.append(p)
            if len(chooseList)>1:
                  delta_E=0
                  maxE=0
                  j=0
                  Ej=0
                  for k in chooseList:
                        Ek=self.__calE(self.xL[k],self.yL[k])
                        delta_E=abs(Ek-Ei)
                        if delta_E>maxE:
                              maxE=delta_E
                              j=k
                              Ej=Ek
                  return j,Ej
            else:
                  #最初始狀態
                  j=self.__randJ(i)
                  Ej=self.__calE(self.xL[j],self.yL[j])
                  return j,Ej

      def __randJ(self,i):
            j=i
            while(j==i):
                  j=random.randint(0,len(self.xL)-1)
            return j

      def __calLH(self,pre_a,j,i):
            if(self.yL[j]!= self.yL[i]):
                  return (max(0,pre_a[j]-pre_a[i]),min(self.C,self.C-pre_a[i]+pre_a[j]))
            else:
                  return (max(0,-self.C+pre_a[i]+pre_a[j]),min(self.C,pre_a[i]+pre_a[j]))

      def __calE(self,x,y):
            #print x,y
            y_,q=self.predict(x)
            return y_-y

      def __calW(self):
            self.w=[0 for i in range(len(self.trainData[0][0]))]
            for i in range(len(self.trainData)):
                  for j in range(len(self.w)):
                        self.w[j]+=self.a[i]*self.yL[i]*self.xL[i][j]

      def __update(self):
            #更新 self.b 和 self.w
            self.__calW()
            #獲得了self.w 下面求b
            #print self.a
            maxf1=-99999
            min1=99999
            for k in range(len(self.trainData)):
                  y_v=self.__Tdot(self.w,self.xL[k])
                  #print y_v
                  if self.yL[k]==-1:
                        if y_v>maxf1:
                              maxf1=y_v
                  else:
                        if y_v<min1:
                              min1=y_v
            self.b=-0.5*(maxf1+min1)

      def predict(self,testData):
            pre_value=0
            #從trainData 改爲 suport_Vector
            for i in range(len(self.trainData)):
                  pre_value+=self.a[i]*self.yL[i]*self.__kernel(self.xL[i],testData)
            pre_value+=self.b
            #print pre_value,"pre_value"
            if pre_value<0:
                  y=-1
            else:
                  y=1
            return y,abs(pre_value-0)

      def save(self):
            pass




def LoadSVM():
      pass複製代碼

另存爲SVM.py

from SVM import *

data=[
        [[1,1],1],
        [[2,1],1],
        [[1,0],1],
        [[3,7],-1],
        [[4,8],-1],
        [[4,10],-1],
      ]
#若是爲gauss核的話  ['Gauss',標準差]
svm=SVM(data,'Line',1000,0.02,0.001)
print (svm.predict([4,0]))
(1, 0.6300000000000001)

print (svm.a)
[0.02, 0.0, 0.0, 0.0, 0.0, 0.02]

print (svm.w)
[-0.06, -0.18000000000000002]

print (svm.b)
0.8700000000000001複製代碼

參考文獻:

https://www.cnblogs.com/pinard/p/6117515.html

http://www.cnblogs.com/tornadomeet/p/3395593.html

https://blog.csdn.net/IT_zxl001/article/details/80488294

https://cuijiahua.com/blog/2017/11/ml9svm_2.html

https://blog.csdn.net/sinat_33829806/article/details/78388025

《機器學習實戰》第6章

相關文章
相關標籤/搜索