1. 程式人生 > >資料探勘領域十大經典演算法之—SVM演算法(超詳細附程式碼)

資料探勘領域十大經典演算法之—SVM演算法(超詳細附程式碼)

簡介 SVM(Support Vector Machine)中文名為支援向量機,是常見的一種判別方法。在機器學習領域,是一個有監督的學習模型,通常用來進行模式識別、分類以及迴歸分析。

相關概念 分類器:分類器就是給定一個樣本的資料,判定這個樣本屬於哪個類別的演算法。例如在股票漲跌預測中,我們認為前一天的交易量和收盤價對於第二天的漲跌是有影響的,那麼分類器就是通過樣本的交易量和收盤價預測第二天的漲跌情況的演算法。

特徵:在分類問題中,輸入到分類器中的資料叫做特徵。以上面的股票漲跌預測問題為例,特徵就是前一天的交易量和收盤價。

線性分類器:線性分類器是分類器中的一種,就是判定分類結果的根據是通過特徵的線性組合得到的,不能通過特徵的非線性運算結果作為判定根據。還以上面的股票漲跌預測問題為例,判斷的依據只能是前一天的交易量和收盤價的線性組合,不能將交易量和收盤價進行開方,平方等運算。

線性分類器起源 在實際應用中,我們往往遇到這樣的問題:給定一些資料點,它們分別屬於兩個不同的類,現在要找到一個線性分類器把這些資料分成兩類。

怎麼分呢?把整個空間劈成兩半唄(讓我想到了盤古)。用二維空間舉個例子,如上圖所示,我們用一條直線把空間切割開來,直線左邊的點屬於類別-1(用三角表示),直線右邊的點屬於類別1(用方塊表示)。

如果用數學語言呢,就是這樣的:空間是由X1和X2組成的二維空間,直線的方程是X1+X2 = 1,用向量符號表示即為[1,1]^{T}[X1,X2]-1=0 。點x在直線左邊的意思是指,當把x放入方程左邊,計算結果小於0。同理,在右邊就是把x放入方程左邊,計算出的結果大於0。都是高中數學知識。

在二維空間中,用一條直線就把空間分割開了:    在三維空間中呢,需要用一個平面把空間切成兩半,對應的方程是X1+X2+X3=1,也就是[1,1,1]^{T}[X1,X2,X3]-1=0 。    在高維(n>3)空間呢?就需要用到n-1維的超平面將空間切割開了。那麼抽象的歸納下:

如果用x表示資料點,用y表示類別(y取1或者-1,代表兩個不同的類),一個線性分類器的學習目標便是要在n維的資料空間中找到一個超平面(hyper plane),把空間切割開,這個超平面的方程可以表示為(W^{T}中的T代表轉置):  W^{T}X+b=0

感知器模型和邏輯迴歸:

常見的線性分類器有感知器模型和邏輯迴歸。上一節舉出的例子是感知器模型,直接給你分好類。有時候,我們除了要知道分類器對於新資料的分類結果,還希望知道分類器對於這次分類的成功概率。邏輯迴歸就可以做這件事情。

邏輯迴歸(雖然稱作迴歸,但是不是一個迴歸方法,卻是一個分類演算法。很蛋疼的說)將線性分類器的超平面方程計算結果通過logistic函式從正負無窮對映到0到1。這樣,對映的結果就可以認為是分類器將x判定為類別1的概率,從而指導後面的學習過程。

舉個例子,看天氣預報,用感知器的天氣預報只會告訴你明天要下雨(y=1),或者明天不下雨(y=-1);而用了邏輯迴歸的天氣預報就能告訴你明天有90%的概率要下雨,10%的概率不下雨。

邏輯迴歸的公式是g(z)=\frac{1}{1+e^{-z}} ,影象大概長這個樣子:    怎麼用呢?比如感知器模型中,將特徵代入判別方程中,如果得到的值是-3,我們可以判定類別是-1(因為-3<0)。而邏輯迴歸中呢,將-3代入g(z),我們就知道,該資料屬於類別1的概率是0.05(近似數值,謝謝),那麼屬於類別-1的概率就是1 – 0.05 = 0.95。也就是用概率的觀點描述這個事情。

支援向量機 VS 感知器和邏輯迴歸 根據上面的討論,我們知道了在多維空間下,用一個超平面就把資料分為了兩類。這個超平面我們叫它為分離超平面。但是這個分離超平面可以有很多個,那麼用哪個呢?    上圖中,對於目前的訓練資料,綠色和黑色的直線(二維特徵空間,分離超平面就是直線啦)都可以很可以很好的進行分類。但是,通過已知資料建立分離超平面的目的,是為了對於未知資料進行分類的。在下圖中,藍色的星星圖案就是新加入的真實資料。    這時候我們就可以看出不同的分離超平面的選擇對於分類效果的影響了。有的綠線會將三個點都劃歸藍色圓圈,有的綠線會將三個點都劃歸紅色正方形。

那麼綠線和黑線留下誰?我們認為,已有的訓練資料中,每個元素距離分離超平面都有一個距離。在新增超平面的時候,儘可能的使最靠近分離超平面的那個元素與超平面的距離變大。這樣,加入新的資料的時候,分的準的概率會最大化。感知器模型和邏輯迴歸都不能很好的完成這個工作,該我們的支援向量機(support vector machine,SVM)出場了。

首先,SVM將函式間隔(\left| W^{T}X+b \right| ,將特徵值代入分離超平面的方程中,得到的絕對值)歸一化,歸一化的目的是除掉取值尺度的影響;其次,對所有元素求到超平面的距離,(這個距離是\frac{\left| W^{T}X+b \right| }{\left| W \right| } ,也就是幾何間隔)。給定一個超平面P,所有樣本距離超平面P的距離可以記為d_{ij}=\frac{\left| W^{T}X+b \right| }{\left| W \right| } ,這其中最小的距離記為D_{P},SVM的作用就是找到D_{P}最大的超平面。

可以看出,大部分資料對於分離超平面都沒有作用,能決定分離超平面的,只是已知的訓練資料中很小的一部分。這與邏輯迴歸有非常大的區別。上圖中,決定黑色的這條最優分離超平面的資料只有下方的兩個紅色的資料點和上方的一個藍色的資料點。這些對於分離超平面有著非常強大影響的資料點也被稱為支援向量(看沒看到,這就是傳說中的支援向量啦,原來如此)。

引入黑科技-核函式 上面說的都是在原始特徵的維度上,能直接找到一條分離超平面將資料完美的分成兩類的情況。但如果找不到呢?

比如,原始的輸入向量是一維的,0< x <1的類別是1,其他情況記做-1。這樣的情況是不可能在1維空間中找到分離超平面的(一維空間中的分離超平面是一個點,aX+b=0)。你用一個點切一下試試?    這就要說到SVM的黑科技—核函式技巧。核函式可以將原始特徵對映到另一個高維特徵空間中,解決原始空間的線性不可分問題。

繼續剛才那個數軸。    如果我們將原始的一維特徵空間對映到二維特徵空間X^{2}和x,那麼就可以找到分離超平面X^{2}-X=0。當X^{2}-X<0的時候,就可以判別為類別1,當X^{2}-X>0 的時候,就可以判別為類別0。如下圖:    再將X^2-X=0映射回原始的特徵空間,就可以知道在0和1之間的例項類別是1,剩下空間上(小於0和大於1)的例項類別都是0啦。    利用特徵對映,就可以將低維空間中的線性不可分問題解決了。是不是很神奇,這就是特徵對映的牛逼之處了。核函式除了能夠完成特徵對映,而且還能把特徵對映之後的內積結果直接返回,大幅度降低了簡化了工作,這就是為啥採用核函式的原因。

SVM三種模型 SVM有三種模型,由簡至繁為

當訓練資料訓練可分時,通過硬間隔最大化,可學習到硬間隔支援向量機,又叫線性可分支援向量機 當訓練資料訓練近似可分時,通過軟間隔最大化,可學習到軟間隔支援向量機,又叫線性支援向量機 當訓練資料訓練不可分時,通過軟間隔最大化及核技巧(kernel trick),可學習到非線性支援向量機 程式碼 程式碼已在github上實現,這裡也貼出來

# encoding=utf-8

import time

import numpy as np import pandas as pd from sklearn.cross_validation import train_test_split from sklearn.metrics import accuracy_score from sklearn import datasets from sklearn import svm

if __name__ == '__main__':

    print('prepare datasets...')     # Iris資料集     # iris=datasets.load_iris()     # features=iris.data     # labels=iris.target

    # MINST資料集     raw_data = pd.read_csv('../data/train_binary.csv', header=0)  # 讀取csv資料,並將第一行視為表頭,返回DataFrame型別     data = raw_data.values     features = data[::, 1::]     labels = data[::, 0]    # 選取33%資料作為測試集,剩餘為訓練集

    train_features, test_features, train_labels, test_labels = train_test_split(features, labels, test_size=0.33, random_state=0)

    time_2=time.time()     print('Start training...')     clf = svm.SVC()  # svm class        clf.fit(train_features, train_labels)  # training the svc model      time_3 = time.time()     print('training cost %f seconds' % (time_3 - time_2))

    print('Start predicting...')     test_predict=clf.predict(test_features)     time_4 = time.time()     print('predicting cost %f seconds' % (time_4 - time_3))

    score = accuracy_score(test_labels, test_predict) print("The accruacy score is %f" % score) 測試資料集為經過二分類處理後的MNIST資料集,獲取地址train_binary.csv

執行結果

è¿éåå¾çæè¿°