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

支持向量机是机器学习领域里最强的几种分类器之一,被广泛的运用于各种分类回归问题,如果不考虑集成学习算法以及近几年出现的深度学习算法,支持向量机的性能可以说是在学习领域具有统治地位,在一些中小型的数据集上它的性能甚至能够超过一些深度学习网络。其基本原理相当简单,但是模型的求解和优化却十分复杂,很难描述清楚,这里我会一步一步,尽我所能分章节的将它总结完善


· 支持向量机:模型篇1–支持向量与间隔
· 支持向量机:模型篇2–支持向量的拉格朗日对偶
· 支持向量机:模型篇3–对偶问题的求解: SMO算法
· 支持向量机:模型篇4–核函数与非线性优化
· 支持向量机:模型篇5–向量机的软间隔拓展
· 支持向量机:代码篇


这里是支持向量机的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_machine

import numpy
import cvxopt
import matplotlib.pyplot as plt

def 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 K

def 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 a

def 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 b

def 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 w

class 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_train
        
def 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()      
        

测试结果

这里写图片描述

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

更多资源下载

微信搜索“老和山算法指南”获取更多下载链接与技术交流群
在这里插入图片描述
有问题可以私信博主,点赞关注的一般都会回复,一起努力,谢谢支持。

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Liangjun_Feng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值