[怕難?]支持向量機SVM基礎實戰篇(一)
這幾篇SVM介紹是從0到1慢慢學會支持向量機,將是滿滿的乾貨,都是我親自寫的,沒有搬運,可以隨我一起從頭瞭解SVM,並在短期內能使用SVM做到想要的分類或者預測~我也將附上自己基礎訓練的完整代碼,建議同我一樣初學者們,自己從頭到尾打一遍,找找手感,代碼不能光看看,實踐出真知!
基本上每本機器學習書籍和資料都會介紹SVM算法,但是更多的書籍是原理類型的,就正如我上一篇文章一樣,然而這是遠遠不夠的,尤其是計算機專業而言,動手操練是最重要的,不過您要是已經是這方面的大佬了,就請略過~ SVM可以做分類和預測,相對做分類的會比較多,尤其是在CV和NLP方向,好下面讓我們由淺到深,一步一步熟悉SVM吧!
一、代碼實現SVM原理:
這個代碼比較長,我只能貼一小部分出來了,這將是真正代碼實現SVM原理,下面會使用SK-learn及其他的庫對SVM的封裝,也就是待會咱們再做掉包俠,先搞懂原理實現~(原理圖解在上一章)
首先我們隨機模擬數據,比如分佈點:x和y座標:(第一第二列)第三列是label 兩類:-1和1
有訓練數據和驗證數據如圖:
接下來是部分關鍵代碼實現(需要源碼的私聊聯繫我):
# 定義數據結構體,用於緩存,提高運行速度
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
其餘代碼暫略,下面看分類結果:
這個是線性分類器,接下來我們繼續深入:
與上文一樣的數據:
代碼實現分類:
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’等,這些核函數原理,使用,特點,和比較,我會在下兩期介紹
結果顯示如圖:
左邊爲原始數據,右邊爲使用linear核函數做的分類;
這是 :precision精確率 recall召回率,和他們的組合計算公式:f1的分數(分別在linear的訓練集和數據集的比較)
接下來使用poly核函數:degree = 3 說明是三階,同樣可以往上加,不過越多越花時間多,但是擬合程度也會很高(過擬合除外)
下面是他的精確率等:
一比較大家就能知道使用非線性算法accuracy = 0.88 比線性算法高, 因爲我的數據是非線性的,使用線性算法分類既容易產生過擬合,準確率還差,使用非線性算法會比較好,真實世界中的處理數據,不僅僅是非線性這麼簡單了,還有多維和噪音,髒數據等等,要考慮的方面也會更多。
接下來再介紹一下解決類型數據不平衡問題:
數據換了一套,代碼改動不大,篇幅問題,暫不贅述,需要的評論區見~
這裏的兩種類別的數據差別很大的,如果您不想降維的話:也就是說您想保留這部分數據,讓其參與訓練中,不會被丟棄(降維)降掉,就可以使用以下參數
'kernel': 'linear', 'class_weight': 'balanced'
便可以解決不平衡問題:
如下:
這是使用參數前的,也就是class - 0這一類是0 的精確率(被丟掉了)
然後使用balanced參數以後(以前版本叫auto):
但還是有一些的誤差,這個還是用很大的進步空間的,以後會慢慢介紹~
今天就介紹這麼多,下面還有很多基礎訓練,大家可以跟着打一下代碼一起熟悉一下,關注博主,下期咱們做交通流量地估計。
不知不覺又打了這麼多字,自己也漸漸的把寫博客養成了習慣,博客奉獻他人的同時,其實也是爲了自己,加深學習知識的印象,然後可以更好的掌握知識,就當是日記寫了,然後大家看到了這裏,別忘記關注了,爲小博主,在線求關~自己的排版和語言風格也還不是很好地體現,我是一個很樂觀幽默地人,希望以後能在文章中歡樂大家,在玩中學!
最後,歡迎大家加入我的Python,機器學習,算法,視覺,NLP交流羣,羣名《往死裏學》,聯繫我的微信,直接私聊我即可!
上海第二工業大學18智能A1 周小夏(CV調包俠)