SVM算法分享,及Python實現

wcwx 9年前發布 | 70K 次閱讀 Python 算法

SVM是什么?

SVM是一種訓練機器學習的算法,可以用于解決分類和回歸問題,同時還使用了一種稱之為kernel trick的技術進行數據的轉換,然后再根據這些轉換信息,在可能的輸出之中找到一個最優的邊界。簡單來說,就是做一些非常復雜的數據轉換工作,然后根據預定義的標簽或者輸出進而計算出如何分離用戶的數據。

是什么讓它變得如此的強大?

當然,對于SVM來說,完全有能力實現分類以及回歸。在這篇文章中,Greg Lamp主要關注如何使用SVM進行分類,特別是非線性的SVM或者SVM使用非線性內核。非線性SVM意味著該算法計算的邊界沒有必要是一條直線,這樣做的好處在于,可以捕獲更多數據點集之間的復雜關系,而無需靠用戶自己來執行困難的轉換。其缺點就是由于更多的運算量,訓練的時間要長很多。

什么是kernel trick?

kernel trick對接收到的數據進行轉換:輸入一些你認為比較明顯的特征進行分類,輸出一些你完全不認識的數據,這個過程就像解開一個DNA鏈。你開始是尋找數據的矢量,然后把它傳給kernel trick,再進行不斷的分解和重組直到形成一個更大的數據集,而且通常你看到的這些數據非常的難以理解。這就是神奇之處,擴展的數據集擁有更明顯的邊界,SVM算法也能夠計算一個更加優化的超平面。

其次,假設你是一個農場主,現在你有一個問題——你需要搭建一個籬笆來防止狼對牛群造成傷害。但是籬笆應該建在哪里呢?如果你是一個以數據為驅動的農場主,那么你就需要在你的牧場上,依據牛群和狼群的位置建立一個“分類器”,比較這幾種(如下圖所示)不同的分類器,我們可以看到SVM完成了一個很完美的解決方案。Greg Lamp認為這個故事漂亮的說明了使用非線性分類器的優勢。顯而易見,邏輯模式以及決策樹模式都是使用了直線方法。

實現代碼如下:farmer.py  Python

import numpy as np
import pylab as pl
from sklearn import svm
from sklearn import linear_model
from sklearn import tree
import pandas as pd
def plot_results_with_hyperplane(clf, clf_name, df, plt_nmbr):
    x_min, x_max = df.x.min() – .5, df.x.max() + .5
    y_min, y_max = df.y.min() – .5, df.y.max() + .5
    # step between points. i.e. [0, 0.02, 0.04, …]
    step = .02
    # to plot the boundary, we’re going to create a matrix of every possible point
    # then label each point as a wolf or cow using our classifier
    xx, yy = np.meshgrid(np.arange(x_min, x_max, step),
np.arange(y_min, y_max, step))
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
    # this gets our predictions back into a matrix
    ZZ = Z.reshape(xx.shape)
    # create a subplot (we’re going to have more than 1 plot on a given image)
    pl.subplot(2, 2, plt_nmbr)
    # plot the boundaries
    pl.pcolormesh(xx, yy, Z, cmap=pl.cm.Paired)
    # plot the wolves and cows
    for animal in df.animal.unique():
        pl.scatter(df[df.animal==animal].x,
                   df[df.animal==animal].y,
                   marker=animal,
                   label=“cows” if animal==”x” else “wolves”,
                   color=‘black’,
                   c=df.animal_type, cmap=pl.cm.Paired)
    pl.title(clf_name)
    pl.legend(loc=“best”)
data = open(“cows_and_wolves.txt”).read()
data = [row.split(‘\t’) for row in data.strip().split(‘\n’)]
animals = []
for y, row in enumerate(data):
    for x, item in enumerate(row):
        # x’s are cows, o’s are wolves
        if item in [‘o’, ‘x’]:
            animals.append([x, y, item])
df = pd.DataFrame(animals, columns=[“x”, “y”, “animal”])
df[‘animal_type’] = df.animal.apply(lambda x: 0 if x==”x” else 1)
# train using the x and y position coordiantes
train_cols = [“x”, “y”]
clfs = {
    “SVM”: svm.SVC(),
    “Logistic” : linear_model.LogisticRegression(),
    “Decision Tree”: tree.DecisionTreeClassifier(),
}
plt_nmbr = 1
for clf_name, clf in clfs.iteritems():
    clf.fit(df[train_cols], df.animal_type)
    plot_results_with_hyperplane(clf, clf_name, df, plt_nmbr)
    plt_nmbr += 1
pl.show()

讓SVM做一些更難的工作吧!

誠然,如果自變量和因變量之間的關系是非線性的,是很難接近SVM的準確性。如果還是難以理解的話,可以看看下面的例子:假設我們有一組數據集,它包含了綠色以及紅色的點集。我們首先標繪一下它們的坐標,這些點集構成了一個具體的形狀——擁有著紅色的輪廓,周圍充斥著綠色(看起來就像孟加拉國的國旗)。如果因為某些原因,我們丟失了數據集當中1/3的部分,那么在我們恢復的時候,我們就希望尋找一種方法,最大程度地實現這丟失1/3部分的輪廓。

那么我們如何推測這丟失1/3的部分最接近什么形狀?一種方式就是建立一種模型,使用剩下接近80%的數據信息作為一個“訓練集”。Greg Lamp選擇三種不同的數據模型分別做了嘗試:

  • 邏輯模型(GLM)
  • 決策樹模型(DT)
  • SVM

Greg Lamp對每種數據模型都進行了訓練,然后再利用這些模型推測丟失1/3部分的數據集。我們可以看看這些不同模型的推測結果:

實現代碼如下:svmflag.py Python

    import numpy as np
    import pylab as pl
    import pandas as pd
    from sklearn import svm
    from sklearn import linear_model
    from sklearn import tree
    from sklearn.metrics import confusion_matrix
    x_min, x_max = 0, 15
    y_min, y_max = 0, 10
    step = .1
    # to plot the boundary, we’re going to create a matrix of every possible point
    # then label each point as a wolf or cow using our classifier
    xx, yy = np.meshgrid(np.arange(x_min, x_max, step), np.arange(y_min, y_max, step))
    df = pd.DataFrame(data={‘x': xx.ravel(), ‘y': yy.ravel()})
    df[‘color_gauge’] = (df.x-7.5)**2 + (df.y-5)**2
    df[‘color’] = df.color_gauge.apply(lambda x: “red” if x <= 15 else “green”)
    df[‘color_as_int’] = df.color.apply(lambda x: 0 if x==”red” else 1)
    print “Points on flag:”
    print df.groupby(‘color’).size()
    print
    figure = 1
    # plot a figure for the entire dataset
    for color in df.color.unique():
        idx = df.color==color
        pl.subplot(2, 2, figure)
        pl.scatter(df[idx].x, df[idx].y, colorcolor=color)
        pl.title(‘Actual’)
    train_idx = df.x < 10
    train = df[train_idx]
    test = df[-train_idx]
    print “Training Set Size: %d” % len(train)
    print “Test Set Size: %d” % len(test)
    # train using the x and y position coordiantes
    cols = [“x”, “y”]
    clfs = {
        “SVM”: svm.SVC(degree=0.5),
        “Logistic” : linear_model.LogisticRegression(),
        “Decision Tree”: tree.DecisionTreeClassifier()
    }
    # racehorse different classifiers and plot the results
    for clf_name, clf in clfs.iteritems():
        figure += 1
        # train the classifier
        clf.fit(train[cols], train.color_as_int)
        # get the predicted values from the test set
        test[‘predicted_color_as_int’] = clf.predict(test[cols])
        test[‘pred_color’]
    = test.predicted_color_as_int.apply(lambda x: “red” if x==0 else “green”)
        # create a new subplot on the plot
        pl.subplot(2, 2, figure)
        # plot each predicted color
        for color in test.pred_color.unique():
            # plot only rows where pred_color is equal to color
            idx = test.pred_color==color
            pl.scatter(test[idx].x, test[idx].y, colorcolor=color)
        # plot the training set as well
        for color in train.color.unique():
            idx = train.color==color
            pl.scatter(train[idx].x, train[idx].y, colorcolor=color)
        # add a dotted line to show the boundary between the training and test set
        # (everything to the right of the line is in the test set)
        #this plots a vertical line
        train_line_y = np.linspace(y_min, y_max) #evenly spaced array from 0 to 10
        train_line_x = np.repeat(10, len(train_line_y))
     #repeat 10 (threshold for traininset) n times
        # add a black, dotted line to the subplot
        pl.plot(train_line_x, train_line_y, ‘k–‘, color=“black”)
        pl.title(clf_name)
        print “Confusion Matrix for %s:” % clf_name
        print confusion_matrix(test.color, test.pred_color)
    pl.show()

結論:

從這些實驗結果來看,毫無疑問,SVM是絕對的優勝者。但是究其原因我們不妨看一下DT模型和GLM模型。很明顯,它們都是使用的直線邊界。Greg Lamp的輸入模型在計算非線性的x, y以及顏色之間的關系時,并沒有包含任何的轉換信息。假如Greg Lamp它們能夠定義一些特定的轉換信息,可以使GLM模型和DT模型能夠輸出更好的效果,他們為什么要浪費時間呢?其實并沒有復雜的轉換或者壓縮,SVM僅僅分析錯了117/5000個點集(高達98%的準確率,對比而言,DT模型是51%,而GLM模型只有12%!)

局限性在哪里?

很多人都有疑問,既然SVM這么強大,但是為什么不能對一切使用SVM呢?很不幸,SVM最神奇的地方恰好也是它最大的軟肋!復雜的數據轉換信息和邊界的產生結果都難以進行闡述。這也是它常常被稱之為“black box”的原因,而GLM模型和DT模型剛好相反,它們很容易進行理解。

 本文由用戶 wcwx 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!