使用Python从零实现多分类SVM( 三 )

我们确保这是一个二进制问题,并且二进制标签按照支持向量机(±1)的假设设置,并且y是一个维数为(N,1)的列向量 。然后求解求解(α?α?…α _n) 的优化问题 。
使用(α?α?…α _n) _来获得在与支持向量对应的任何索引处为1的标志数组 , 然后可以通过仅对支持向量和(x?,y?)的边界支持向量的索引求和来应用预测方程 。我们确实假设非支持向量可能不完全具有α=0,如果它的α≤1e-3,那么这是近似为零(CVXOPT结果可能不是最终精确的) 。同样假设非边际支持向量可能不完全具有α=C 。
下面就是预测的方法,预测方程为:

使用Python从零实现多分类SVM

文章插图
@SVMClass def predict(self, X_t):if self.multiclass: return self.multi_predict(X_t)# compute (x?, y?)x?, y? = self.X[self.margin_sv, np.newaxis], self.y[self.margin_sv]# find support vectorsαs, y, X= self.αs[self.is_sv], self.y[self.is_sv], self.X[self.is_sv]# compute the second termb = y? - np.sum(αs * y * self.kernel(X, x?, self.k), axis=0)# compute the scorescore = np.sum(αs * y * self.kernel(X, X_t, self.k), axis=0) + breturn np.sign(score).astype(int), score我们还可以实现一个评估方法来计算精度(在上面的fit中使用) 。
@SVMClass def evaluate(self, X,y):outputs, _ = self.predict(X)accuracy = np.sum(outputs == y) / len(y)return round(accuracy, 2)最后测试我们的完整代码:
from sklearn.datasets import make_classification import numpy as np# Load the dataset np.random.seed(1) X, y = make_classification(n_samples=2500, n_features=5,n_redundant=0, n_informative=5,n_classes=2, class_sep=0.3)# Test Implemented SVM svm = SVM(kernel='rbf', k=1) svm.fit(X, y, eval_train=True)y_pred, _ = svm.predict(X) print(f"Accuracy: {np.sum(y==y_pred)/y.shape[0]}") #0.9108# Test with Scikit from sklearn.svm import SVC clf = SVC(kernel='rbf', C=1, gamma=1) clf.fit(X, y) y_pred = clf.predict(X) print(f"Accuracy: {sum(y==y_pred)/y.shape[0]}")#0.9108多分类SVM我们都知道SVM的目标是二元分类,如果要将模型推广到多类则需要为每个类训练一个二元SVM分类器,然后对每个类进行循环,并将属于它的点重新标记为+1,并将所有其他类的点重新标记为-1 。
当给定k个类时,训练的结果是k个分类器,其中第i个分类器在数据上进行训练,第i个分类器被标记为+1,所有其他分类器被标记为-1 。
@SVMClass def multi_fit(self, X, y, eval_train=False):self.k = len(np.unique(y))# number of classes# for each pair of classesfor i in range(self.k):# get the data for the pairXs, Ys = X, copy.copy(y)# change the labels to -1 and 1Ys[Ys!=i], Ys[Ys==i] = -1, +1# fit the classifierclf = SVM(kernel=self.kernel_str, C=self.C, k=self.k)clf.fit(Xs, Ys)# save the classifierself.clfs.Append(clf)if eval_train:print(f"Finished training with accuracy {self.evaluate(X, y)}")然后,为了对新示例执行预测,我们选择相应分类器最自信(得分最高)的类 。
@SVMClass def multi_predict(self, X):# get the predictions from all classifiersN = X.shape[0]preds = np.zeros((N, self.k))for i, clf in enumerate(self.clfs):_, preds[:, i] = clf.predict(X)# get the argmax and the corresponding scorereturn np.argmax(preds, axis=1), np.max(preds, axis=1)完整测试代码:
from sklearn.datasets import make_classification import numpy as np# Load the dataset np.random.seed(1) X, y = make_classification(n_samples=500, n_features=2,n_redundant=0, n_informative=2,n_classes=4, n_clusters_per_class=1,class_sep=0.3)# Test SVM svm = SVM(kernel='rbf', k=4) svm.fit(X, y, eval_train=True)y_pred = svm.predict(X) print(f"Accuracy: {np.sum(y==y_pred)/y.shape[0]}") # 0.65# Test with Scikit from sklearn.multiclass import OneVsRestClassifier from sklearn.svm import SVCclf = OneVsRestClassifier(SVC(kernel='rbf', C=1, gamma=4)).fit(X, y) y_pred = clf.predict(X) print(f"Accuracy: {sum(y==y_pred)/y.shape[0]}")# 0.65绘制每个决策区域的图示,得到以下图:
使用Python从零实现多分类SVM

文章插图
可以看到,我们的实现与Sci-kit Learn结果相当,说明在算法实现上没有问题 。注意:SVM默认支持OVR(没有如上所示的显式调用) , 它是特定于SVM的进一步优化 。
总结我们使用Python实现了支持向量机(SVM)学习算法,并且包括了软边界和常用的三个核函数 。我们还将SVM扩展到多分类的场景 , 并使用Sci-kit Learn验证了我们的实现 。希望通过本文你可以更好的了解SVM 。




推荐阅读