机器学习教程 之 支持向量机:代码篇(二分类、非线性、软间隔)

来源:互联网 发布:计算机的算法都有哪些 编辑:程序博客网 时间:2024/06/07 01:59

这里是支持向量机的python3代码,考虑了非线性分类与软间隔问题,支持二分类数据集,关于支持向量机的原理,等有空再整理写出

#!/usr/bin/env python3# -*-coding: utf-8-*-# Author : LiangjunFeng# Blog   : http://my.csdn.net/Liangjun_Feng# GitHub : https://www.github.com/LiangjunFeng# File   : support_vector_machine.py# Date   : 2017/09/21 11:12# Version: 0.1# Description: support_vector_machineimport numpyimport cvxoptimport matplotlib.pyplot as pltdef linearKernel(x1,x2):          #线性核函数    return numpy.dot(x1,x2)def gaussianKernel(x1,x2,sigma = 3):        #高斯核函数    return numpy.exp(-numpy.linalg.norm(x1-x2)**2/(2*(sigma ** 2)))def makeKernelMatrix(input_,kernel,par = 3):       #根据核函数核输入数据,创建核矩阵    num = input_.shape[0]    K = numpy.zeros((num,num))    for i in range(num):        for j in range(num):            if kernel == 'linearKernel':                K[i,j] = linearKernel(input_[i],input_[j])            else:                K[i,j] = gaussianKernel(input_[i],input_[j],par)    return Kdef calculateA(input_,label,C,K):                  #利用cvxopt求解拉格朗日乘法子    num = input_.shape[0]    P = cvxopt.matrix(numpy.outer(label,label)*K)    q = cvxopt.matrix(numpy.ones(num)*-1)    A = cvxopt.matrix(label,(1,num))    b = cvxopt.matrix(0.0)    if C is None:        G = cvxopt.matrix(numpy.diag(numpy.ones(num)*-1))        h = cvxopt.matrix(numpy.zeros(num))    else:        temp1 = numpy.diag(numpy.ones(num)*-1)        temp2 = bp.identity(num)        G = cvxopt.matrix(numpy.vstack(temp1,temp2))        temp1 = numpy.zeros(num)        temp2 = numpy.ones(num)*self.C        h = cvxopt.matrix(numpy.hstack(temp1,temp2))     #P\q\A\b\G\h均为规划参数    solution = cvxopt.solvers.qp(P,q,G,h,A,b)            #解模型    a = numpy.ravel(solution['x'])                       #利用ravel函数将a转化为1维向量    return adef calculateB(a,supportVectorLabel,supportVector,K,indexis):   #计算模型偏置b    b = 0    for i in range(len(a)):        b += supportVectorLabel[i]        b -= numpy.sum(a*supportVectorLabel*K[indexis[i],supportVector])    b /= len(a)                                          #求解所有输入例的偏差均值为b    return bdef calculateWeight(kernel,features,a,supportVector,supportVectorLabel):    #计算模型权重w    if kernel == linearKernel:                           #线性核时按线性方式计算w        w = numpy.zeros(features)        for i in range(len(a)):            w += a[i]*supportVectorLabel[i]*supportVector[i]    else:                                                #非线性核无需计算后面会直接根据核矩阵算出结果        w = None    return wclass SVM:    def __init__(self,kernel = linearKernel,C = None):  #初始化        self.kernel = kernel        self.C = C        self.a = None        self.b = 0        self.w = []        self.supportVector = []        self.supportVectorLabel = []        if self.C is not None:            self.C = float(self.C)    def fit(self,input_,label):                        #拟合函数        samples,features = input_.shape        K = makeKernelMatrix(input_,self.kernel)       #计算核矩阵        a = calculateA(input_,label,self.C,K)          #计算拉格朗日乘法子        supportVector = a > 1e-5                       #小于1e-5的a判定为0,supportVector为一个boolen型列表,记录哪些数据支持向量        indexis = numpy.arange(len(a))[supportVector]  #支持向量的下标        self.a = a[supportVector]                      #支持向量的a        self.supportVector = input_[supportVector]     #支持向量        self.supportVectorLabel = label[supportVector] #支持向量的标签        print(len(self.a),' support vectors out of ',samples,' points')        self.b = calculateB(self.a,self.supportVectorLabel,supportVector,K,indexis)    #计算模型偏置b        self.w = calculateWeight(self.kernel,features,self.a,self.supportVector,self.supportVectorLabel)  #计算权重w    def predict(self,input_):                         #预测分类函数        if self.w is not None:                               return numpy.dot(inpt_,self.w) + self.b        else:            predictLabel = numpy.zeros(len(input_))            for i in range(len(input_)):                s  = 0                for a,sv_y,sv in zip(self.a,self.supportVectorLabel,self.supportVector):                    s += a * sv_y * self.kernel(input_[i],sv)                predictLabel[i] = s            return numpy.sign(predictLabel+self.b)def gen_non_lin_separable_data():                     #产生一组数据    mean1 = [-1, 2]    mean2 = [1, -1]    mean3 = [4, -4]    mean4 = [-4, 4]    cov = [[1.0,0.8], [0.8, 1.0]]    X1 = numpy.random.multivariate_normal(mean1, cov, 60)    X1 = numpy.vstack((X1, numpy.random.multivariate_normal(mean3, cov, 60)))    y1 = numpy.ones(len(X1))    X2 = numpy.random.multivariate_normal(mean2, cov, 60)    X2 = numpy.vstack((X2, numpy.random.multivariate_normal(mean4, cov, 60)))    y2 = numpy.ones(len(X2)) * -1    return X1, y1, X2, y2 def split_train(X1, y1, X2, y2):                     #从产生的数据中分出训练集     X1_train = X1[:90]     y1_train = y1[:90]     X2_train = X2[:90]     y2_train = y2[:90]     X_train = numpy.vstack((X1_train, X2_train))     y_train = numpy.hstack((y1_train, y2_train))     return X_train, y_traindef split_test(X1, y1, X2, y2):                      #从产生的数据中分出测试集     X1_test = X1[90:]     y1_test = y1[90:]     X2_test = X2[90:]     y2_test = y2[90:]     X_test = numpy.vstack((X1_test, X2_test))     y_test = numpy.hstack((y1_test, y2_test))     return X_test, y_test     def test_non_linear():                              #测试非线性分类,gauss核     X1, y1, X2, y2 = gen_non_lin_separable_data()     X_train, y_train = split_train(X1, y1, X2, y2)     print(y_train,'$$$')     X_test, y_test = split_test(X1, y1, X2, y2)     clf = SVM(gaussianKernel)     X_train = numpy.array(X_train)     y_train = numpy.array(y_train)     print(y_train,'$$$')     clf.fit(X_train, y_train)     y_predict = clf.predict(X_test)     plt.title('scatter diagram')     for i in range(len(X_test)):         if y_predict[i] == 1:             plt.plot(X_test[i,0],X_test[i,1],'ro')         else:             plt.plot(X_test[i,0],X_test[i,1],'go')     plt.show()if __name__ == "__main__":    test_non_linear()      

测试结果

这里写图片描述

有什么不明白的地方欢迎打扰

阅读全文
0 0