[怕難?]支持向量機SVM基礎實戰篇(一)

[怕難?]支持向量機SVM基礎實戰篇(一)

​ 這幾篇SVM介紹是從0到1慢慢學會支持向量機,將是滿滿的乾貨,都是我親自寫的,沒有搬運,可以隨我一起從頭瞭解SVM,並在短期內能使用SVM做到想要的分類或者預測~我也將附上自己基礎訓練的完整代碼,建議同我一樣初學者們,自己從頭到尾打一遍,找找手感,代碼不能光看看,實踐出真知!

​ 基本上每本機器學習書籍和資料都會介紹SVM算法,但是更多的書籍是原理類型的,就正如我上一篇文章一樣,然而這是遠遠不夠的,尤其是計算機專業而言,動手操練是最重要的,不過您要是已經是這方面的大佬了,就請略過~ SVM可以做分類和預測,相對做分類的會比較多,尤其是在CV和NLP方向,好下面讓我們由淺到深,一步一步熟悉SVM吧!


一、代碼實現SVM原理:

這個代碼比較長,我只能貼一小部分出來了,這將是真正代碼實現SVM原理,下面會使用SK-learn及其他的庫對SVM的封裝,也就是待會咱們再做掉包俠,先搞懂原理實現~(原理圖解在上一章)

首先我們隨機模擬數據,比如分佈點:x和y座標:(第一第二列)第三列是label 兩類:-1和1

有訓練數據和驗證數據如圖:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ajMOTQmy-1587631206529)(D:\CSDN\pic\支持向量機SVM基礎實戰篇\支持向量機SVM基礎實戰篇.png)]

接下來是部分關鍵代碼實現(需要源碼的私聊聯繫我):

# 定義數據結構體,用於緩存,提高運行速度
class optStruct:
    def __init__(self, dataSet, labelSet, C, toler, kTup):
        self.dataMat = np.mat(dataSet)  # 原始數據,轉換成m*n矩陣
        self.labelMat = np.mat(labelSet).T  # 標籤數據 m*1矩陣
        self.C = C  # 懲罰參數,C越大,容忍噪聲度小,需要優化;反之,容忍噪聲度高,不需要優化;
        # 所有的拉格朗日乘子都被限制在了以C爲邊長的矩形裏
        self.toler = toler  # 容忍度
        self.m = np.shape(self.dataMat)[0]  # 原始數據行長度
        self.alphas = np.mat(np.zeros((self.m, 1)))  # alpha係數,m*1矩陣
        self.b = 0  # 偏置
        self.eCache = np.mat(np.zeros((self.m, 2)))  # 保存原始數據每行的預測值
        self.K = np.mat(np.zeros((self.m, self.m)))  # 核轉換矩陣 m*m
        for i in range(self.m):
            self.K[:, i] = kernelTrans(self.dataMat, self.dataMat[i, :], kTup)
# 從文件獲取特徵數據,標籤數據
def loadDataSet(fileName):
    dataSet = [];
    labelSet = []
    fr = open(fileName)
    for line in fr.readlines():
        # 分割
        print(line)

        lineArr = line.strip().split('    ')
        print(lineArr)
        lineArr = list(map(float, lineArr))
        dataSet.append([lineArr[0], lineArr[1]])
        labelSet.append(lineArr[2])
    return dataSet, labelSet


# 計算 w 權重係數
def calWs(alphas, dataSet, labelSet):
    dataMat = np.mat(dataSet)
    # 1*100 => 100*1
    labelMat = np.mat(labelSet).T
    m, n = np.shape(dataMat)
    w = np.zeros((n, 1))
    for i in range(m):
        w += np.multiply(alphas[i] * labelMat[i], dataMat[i, :].T)
    return w

其餘代碼暫略,下面看分類結果:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-r1hnf9pg-1587631206531)(D:\CSDN\pic\支持向量機SVM基礎實戰篇\1587290152050.png)]

這個是線性分類器,接下來我們繼續深入:

與上文一樣的數據:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-IXv5W6Sy-1587631206534)(D:\CSDN\pic\支持向量機SVM基礎實戰篇\1587290810761.png)]

​ 代碼實現分類:

import numpy as np
import matplotlib.pyplot as plt
# from .utilities import *
# 獲取數據
def load_file(input_file):   
    x = []
    y = []
    with open(input_file, "r") as f:
        for line in f.readlines():
            data = [float(x) for x in line.split(',')]
            x.append(data[:-1])
            y.append(data[-1])
    X = np.array(x)
    y = np.array(y)

    return X, y
input_file = 'data_multivar.txt'

X, y = load_file(input_file)

class_0 = np.array([X[i] for i in range(len(X)) if y[i] == 0])
class_1 = np.array([X[i] for i in range(len(X)) if y[i] == 1])

plt.figure()
plt.scatter(class_0[:, 0], class_0[:, 1], facecolor='black', edgecolors='black',marker='s')
plt.scatter(class_1[:, 0], class_1[:, 1], facecolor='None', edgecolors='black',marker='s')
plt.title('Input data')
plt.show()

#############################################
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
# 數據可視化
def plot_classifier(classifier, X, y, title='Classifier boundaries', annotate=False):
    # define ranges to plot the figure
    x_min, x_max = min(X[:, 0]) - 1.0, max(X[:, 0]) + 1.0
    y_min, y_max = min(X[:, 1]) - 1.0, max(X[:, 1]) + 1.0
    step_size = 0.01
    x_values, y_values = np.meshgrid(np.arange(x_min, x_max, step_size), np.arange(y_min, y_max, step_size))
    mesh_output = classifier.predict(np.c_[x_values.ravel(), y_values.ravel()])
    mesh_output = mesh_output.reshape(x_values.shape)
    plt.figure()
    plt.title(title)

    plt.pcolormesh(x_values, y_values, mesh_output, cmap=plt.cm.gray)

    plt.scatter(X[:, 0], X[:, 1], c=y, s=80, edgecolors='black', linewidth=1, cmap=plt.cm.Paired)

    plt.xlim(x_values.min(), x_values.max())
    plt.ylim(y_values.min(), y_values.max())

    plt.xticks(())
    plt.yticks(())

    if annotate:
        for x, y in zip(X[:, 0], X[:, 1]):
            # Full documentation of the function available here:
            # http://matplotlib.org/api/text_api.html#matplotlib.text.Annotation
            plt.annotate(
                '(' + str(round(x, 1)) + ',' + str(round(y, 1)) + ')',
                xy=(x, y), xytext=(-15, 15),
                textcoords='offset points',
                horizontalalignment='right',
                verticalalignment='bottom',
                bbox=dict(boxstyle='round,pad=0.6', fc='white', alpha=0.8),
                arrowprops=dict(arrowstyle='-', connectionstyle='arc3,rad=0'))

X_train, X_test, y_train, y_test = train_test_split(X, y,test_size=0.25, random_state=5)
params = {'kernel': 'linear'}  # 線性分類器
# params ={'kernel': 'poly', 'degree': 3} # 非線性分類器
classfier = SVC(**params)
classfier.fit(X_train, y_train)
plot_classifier(classfier, X_train, y_train, 'Training dataset')
plt.show()
##################################################
y_test_pred = classfier.predict(X_test)
plot_classifier(classfier, X_test, y_test, 'Test dataset')
plt.show()
##################################################
from sklearn.metrics import classification_report
target_names = ['class-' + str(int(i)) for i in set(y)]
print("\nClassifier performance on training dataset\n")
print(classification_report(y_train, classfier.predict(X_train), target_names=target_names))
print("#"*30 + "\n")

print("#"*30)
print("\nClassification report on test dataset\n")
print(classification_report(y_test, y_test_pred, target_names=target_names))
print("#"*30 + "\n")

plt.show()


代碼說明:

params = {'kernel': 'linear'}  # 線性分類器
params ={'kernel': 'poly', 'degree': 3} # 非線性分類器

其中:kernel: poly是多項式核函數大家學過機器學習應該都學過polynomial regression吧就是多元線性迴歸,

這裏的核函數除了可以使用linear 和poly 還可以使用sigmod和徑向基核函數kernel=‘rbf’等,這些核函數原理,使用,特點,和比較,我會在下兩期介紹

結果顯示如圖:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qZPBC2j1-1587631206538)(D:\CSDN\pic\支持向量機SVM基礎實戰篇\1587291783423.png)]

左邊爲原始數據,右邊爲使用linear核函數做的分類;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-AUak1d08-1587631206541)(D:\CSDN\pic\支持向量機SVM基礎實戰篇\1587291944656.png)]

這是 :precision精確率 recall召回率,和他們的組合計算公式:f1的分數(分別在linear的訓練集和數據集的比較)

接下來使用poly核函數:degree = 3 說明是三階,同樣可以往上加,不過越多越花時間多,但是擬合程度也會很高(過擬合除外)

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-IaCI5Wp7-1587631206543)(D:\CSDN\pic\支持向量機SVM基礎實戰篇\1587292217550.png)]

下面是他的精確率等:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-gYX1yglr-1587631206546)(D:\CSDN\pic\支持向量機SVM基礎實戰篇\1587292269928.png)]

一比較大家就能知道使用非線性算法accuracy = 0.88 比線性算法高, 因爲我的數據是非線性的,使用線性算法分類既容易產生過擬合,準確率還差,使用非線性算法會比較好,真實世界中的處理數據,不僅僅是非線性這麼簡單了,還有多維和噪音,髒數據等等,要考慮的方面也會更多。


接下來再介紹一下解決類型數據不平衡問題:

數據換了一套,代碼改動不大,篇幅問題,暫不贅述,需要的評論區見~

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-5fm4Us1B-1587631206548)(D:\CSDN\pic\支持向量機SVM基礎實戰篇\1587293076377.png)]

這裏的兩種類別的數據差別很大的,如果您不想降維的話:也就是說您想保留這部分數據,讓其參與訓練中,不會被丟棄(降維)降掉,就可以使用以下參數

'kernel': 'linear', 'class_weight': 'balanced'

便可以解決不平衡問題:

如下:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-NAQTIsWE-1587631206549)(D:\CSDN\pic\支持向量機SVM基礎實戰篇\1587293272693.png)]

這是使用參數前的,也就是class - 0這一類是0 的精確率(被丟掉了)

然後使用balanced參數以後(以前版本叫auto):
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-5UMdaEbi-1587631206553)(D:\CSDN\pic\支持向量機SVM基礎實戰篇\1587293348903.png)]

但還是有一些的誤差,這個還是用很大的進步空間的,以後會慢慢介紹~

今天就介紹這麼多,下面還有很多基礎訓練,大家可以跟着打一下代碼一起熟悉一下,關注博主,下期咱們做交通流量地估計。

不知不覺又打了這麼多字,自己也漸漸的把寫博客養成了習慣,博客奉獻他人的同時,其實也是爲了自己,加深學習知識的印象,然後可以更好的掌握知識,就當是日記寫了,然後大家看到了這裏,別忘記關注了,爲小博主,在線求關~自己的排版和語言風格也還不是很好地體現,我是一個很樂觀幽默地人,希望以後能在文章中歡樂大家,在玩中學!

最後,歡迎大家加入我的Python,機器學習,算法,視覺,NLP交流羣,羣名《往死裏學》,聯繫我的微信,直接私聊我即可!

上海第二工業大學18智能A1 周小夏(CV調包俠)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章