精华内容
下载资源
问答
  • 支持向量机SVM)的python简单实现
    千次阅读
    2021-11-01 09:16:51

    支持向量机(SVM)的python简单实现

    1

    由于开题方向的改变,最近在学习入门深度学习的东西,主要看的是邱锡鹏大佬的b站网课,但有时候网课看多了感觉学到的都是空空的理论,终究还是应该自己动手试验一下。

    自己动手写了一些关于SVM(支持向量机)的代码
    环境为python3

    import random
    from random import sample
    import matplotlib.pyplot as plt
    

    先说好实现的都是很简单的东西,没有用梯度下降法之类的,用的知识简单穷举。只是从原理上实现了一下,没什么干货,代码如下。

    import random
    from random import sample
    import matplotlib.pyplot as plt
    
    def point_margin(x1,x2,w,b):#计算间隔margin
        margin = (w*x1-x2+b)*(w*x1-x2+b)/(w*w+1)
        return margin
    
    def loss_function(real_data_x1,raw_data_x2,tag_y,w,b):#设置损失函数,这里用的是平方损失函数
        judge = raw_data_x2 -(w*real_data_x1 + b)
        if tag_y * judge > 0:
            loss = 0
        else:
            loss = (tag_y * judge) * (tag_y * judge)
        return loss
    
    w = 2
    pointnum = 1000
    x1_real_data = []
    x2_real_data = []
    x2_raw_data = []
    y_data = []
    for i in range(0,pointnum):   #制作真值数据,用的是x2 = w*x1
        x1_real_data.append(i)
        x2_real_data.append(w * i)
    
    for i in range(0,pointnum):   #增加噪声
        rawdata = x2_real_data[i] + random.gauss(0,10) + sample([40.0, -40.0], 1)[0] #增加了高斯噪声以及一个偏移量,用于支持向量机挑选最佳分类超平面
        x2_raw_data.append(rawdata)
        if rawdata > i+i: #制作标签
            y_data.append(1)
        else:
            y_data.append(-1)
    
    # for i in range(0,100):
    #     print(x1_real_data[i],x2_raw_data[i],y_data[i])
    
    # losssum = 0
    # for j in range(0,100):
    #     losssum = losssum + loss_function(x1_real_data[j],y_data[j],w,1)
    #     print(losssum)
    bmin = -30
    bmax = 31
    
    good_b = []
    for i in range(bmin,bmax):
        print('b = ',i)
        losssum = 0
        for j in range(0,pointnum):
            losssum = losssum + loss_function(x1_real_data[j],x2_raw_data[j],y_data[j],w,i)
        if losssum ==0:
            good_b.append(i)  #记录损失函数为0的b值
        print('loss = ',losssum)
    
    print(good_b)
    
    plt.xlim(xmax=225,xmin=-50)
    plt.ylim(ymax=250,ymin=-50)
    plt.plot(x1_real_data,x2_raw_data,'ro')
    for i in range(0,pointnum):
        plt.annotate(y_data[i], xy = (x1_real_data[i], x2_raw_data[i]), xytext = (x1_real_data[i]+0.1, x2_raw_data[i]+0.1)) # 将标签显示在散点上
    
    
    
    for i in range(bmin,bmax,10):
        x1 = [-100,250]
        x2 = [x1[0] + x1[0] + i,x1[1] + x1[1] + i]
        plt.plot(x1,x2)   #显示一些辅助线便于看出SVM的意义
    plt.show()
    
    min_margin = [] #记录每一个b值对应的最小距离
    for i in range(0,len(good_b)):
        margin = 1000
        b = good_b[i]
        for j in range(0,pointnum):
            this_margin = point_margin(x1_real_data[j],x2_raw_data[j],w,b)
            if this_margin < margin:
                margin = this_margin
        min_margin.append(margin)
    
    print(min_margin)
    
    plt.plot(good_b,min_margin,'ro') #画出b值与最小距离对应的散点图
    plt.show()
    
    更多相关内容
  • 支持向量机(support vector machines, SVM)是一种二分类模型,它的基本模型是定义在特征空间上的间隔最大的线性分类器,间隔最大使它有别于感知SVM还包括核技巧,这使它成为实质上的非线性分类器。SVM的的学习...
  • SVM.py,支持向量机python 代码实现
  • SVM支持向量机Python代码,更改训练数据集和测试数据集可用
  • python实现SVM支持向量机代码CSV文件。elativeLayout xmlns:android= http: //schemas.android.com/apk/res/android android:layout_width= fill_parent android:layout_height= f...
  • 题目是将图片库中的纹理图片裁剪成九份,其中五份做训练集,四份做测试集,先提取图片LBP特征 ,最后用svm支持向量机进行学习,在预测测试集里的图片是哪一类纹理。 正常情况下是需要调参的,即调整SVM的参数,但图...
  • SVM支持向量机python实现

    千次阅读 2021-01-23 10:35:47
    这两天终于实现了支持向量机,这里想把代码分享给大家。 代码主要参考了两个网友的实现,这里给出参考的网页链接:1)参考代码1;2)参考代码2。 参考的两个代码都有比较模糊的地方。而我的代码也没好到哪里去,但是...

    写在前面

    博主现在在学《统计学习方法》这本书,折腾支持向量机也有半个月多了,之前一直想要把支持向量机搞懂,所以就想集中一段时间来学支持向量机,但是因为懒惰,断断续续地磨了很久。这两天终于实现了支持向量机,这里想把代码分享给大家。
    代码主要参考了两个网友的实现,这里给出参考的网页链接:1)参考代码1;2)参考代码2
    参考的两个代码都有比较模糊的地方。而我的代码也没好到哪里去,但是代码中每个地方对应于什么内容都有注释,相对会比较清晰些。我也给出了两个小的数据集用于训练,数据集的特征都是2维的,所以训练完后可以画出决策边界,就没用测试集了,因为直接看决策边界的效果也比较清楚。其中第1个训练集是来自于是「参考代码2」的,第2个训练集是吴恩达机器学习作业6中的。我会上传到资源,供大家下载测试。
    对于支持向量机的内容,我这里不做详细的讲解,因为网上也有挺多不错的讲解了,我这里给出我自己的学习SVM用到的资料:
    1)《统计学习方法》
    2)零基础学SVM
    3)支持向量机(SVM)原理剖析及实现
    4)李航统计学习之SVM支持向量机+SMO算法数学推导
    课本上有些地方没有说清楚,所以另外找些学习资料还是很有必要的,但是我还是有些地方不明白呀。刚开始学支持向量机的同学,强烈建议先看「零基础学SVM」,这里面讲清楚了对偶问题。然后软间隔和核函数那里,可以看最后两个资料,最后的那个视频资料我觉得很不错,跟着视频公式推下来,多看几遍就差不多了。个人觉得支持向量机还是有一定难度的,需要花点时间来学,反正我是真的花了挺多时间的。

    代码思路说明

    这个代码我是按照《统计学习方法》中SMO算法的描述来实现的,代码的整个框架其实就是两个 α \alpha α变量的选择。
    1)关于第一个 α \alpha α的选择,书中说首先遍历所有满足条件 0 < α i < C 0<\alpha_i<C 0<αi<C的样本点,即在间隔边界上的支持向量点,检验它们是否满足KKT条件。如果这些样本点都满足KKT条件, 那么遍历整个训练集,检验它们是否满足KKT条件。我没有严格按照这个步骤来,初始时,因为所有的 α \alpha α都为 0 0 0,所以首先是直接遍历整个训练集来选出第一个 α \alpha α,这样每个样本都可以成为第一个 α \alpha α,都有机会进行更新。这样运行一轮后,有些 α \alpha α就已经被更新了,不再为0,那么下一轮就可以从训练集中选出所有满足 0 < α i < C 0<\alpha_i<C 0<αi<C的样本(支持向量),然后遍历这些样本,让每个支持向量样本的 α \alpha α都作为第一个 α \alpha α变量继续进行更新。每一轮的遍历都会记录参数的更改次数,如果遍历支持向量样本时,修改次数为 0 0 0,说明所有的支持向量样本点都满足KKT条件,那么后面就转为整个训练集的遍历。如果遍历整个数据集修改次数为 0 0 0,说明收敛了,结束训练。如果不为 0 0 0,说明有参数更新,下一轮就转为遍历支持向量样本。所以 α 1 \alpha_1 α1的选择是在整个训练集和支持向量集的交替遍历中进行,具体见下面的代码。这个思路是「参考代码2」的。
    2)关于第二个 α \alpha α的选择,书中说是希望选择的第二个 α \alpha α能使 α 2 \alpha_2 α2有足够大变化,即使 ∣ E 1 − E 2 ∣ \vert E_1-E_2 \vert E1E2最大。那么这里我就直接把 E 1 E_1 E1与所有样本的 E E E值作差,然后选出使 ∣ E 1 − E ∣ \vert E_1-E \vert E1E最大的样本作为第2个 α \alpha α变量。之后,就是对 α 1 \alpha_1 α1 α 2 \alpha_2 α2 E 1 E_1 E1 E 2 E_2 E2等的更新了。直接看代码可能思路会更清晰些,如果有不太明白的,直接评论里问。
    参数的话我没调,核函数的 σ \sigma σ设为0.1, C C C设为200。挺多代码都这么设,画出的决策边界结果也还可以。

    训练结果图

    dataset_1

    原始数据集分布
    dataset_1_数据原始分布
    决策边界
    dataset_1_决策边界

    dataset_2

    原始数据集分布
    dataset_2_数据原始分布
    决策边界
    dataset_2_决策边界

    数据集下载

    数据集是.mat文件,使用scipy模块来读取文件。
    两个数据集都为2维,样本数分别为100和863。
    数据集

    代码

    我写python代码习惯在句尾加’;’,请见谅~
    本代码中包括打印原始数据集、支持向量和决策边界,直接调用对应的方法即可。
    代码直接复制到jupyter notebook就能运行,最好把代码分开,不要全放在一个代码框中。需要修改的只有数据集的路径。

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import scipy.io as scio
    import random
    
    def load_data(path):
        """
        读取数据
        param
        path: 数据路径
        """
        
        data = scio.loadmat(path);
        X_train = data1['X'];
        y_train = data1['y'];
        y_train = y_train1.reshape(-1);  # 标签转为向量
        return X_train, y_train;
    
    class SVM:
        def __init__(self, train_data, train_label, sigma = 0.1, C = 100, epsilon = 0.0001, iter_time = 30):
            """
            初始化函数
            param
            train_data: 训练集
            train_label: 训练标签
            sigma: 高斯核函数的参数
            C: 软间隔的惩罚系数
            epsilon: 精度
            iter_time: 迭代次数
            """
            
            self.train_data = train_data;  # 训练特征集
            self.train_label = train_label;  # 训练标签
            self.sigma = sigma;  # 高斯核函数参数
            self.C = C;  # 惩罚项系数
            self.epsilon = epsilon;  # 精确值
            self.iter_time = iter_time;  # 迭代次数
            
            self.G = np.zeros(train_data.shape[0]);  # G值
            self.E = -1 * train_label.copy();  # E值
            self.alpha = np.zeros(train_data.shape[0]);  # 拉格朗日参数
            self.b = 0;  
            self.m = train_data.shape[0];  # 样本数
            
            self.supportVecIndex = [];  # 支持向量
        
        def gaussian_kernel(self, i):
            """
            高斯核函数,向量化计算K(j,i),即一次性计算出K(1,i), K(2,i),...,K(m,i),m是样本数
            param
            i: 需要计算的那个样本的编号
            return
            K: 是i与每个样本的核函数结果向量
            """
            
            K = np.exp(-1 * np.sum((self.train_data - self.train_data[i])**2, axis = 1) / (2 * self.sigma**2));
            return K;
        
        def single_gaussian_kernel(self, i, j):
            """
            计算单个高斯核函数,不使用向量化,单独计算K(i,j)
            param
            i:1个样本编号
            j:2个样本编号
            """
            K = np.exp(-1 * np.sum((self.train_data[i] - self.train_data[j])**2) / (2 * (self.sigma ** 2)));
            return K;
        
        def compute_G(self, i):
            """
            计算第i个样本的G值
            param
            i: 计算的那个样本的编号
            """
            
            K_i = self.gaussian_kernel(i);  # 计算这个样本的高斯核函数结果
            G = np.sum(self.alpha * self.train_label * K_i) + self.b;
            return G;
        
        def compute_E(self, i):
            """
            计算第i个样本的E值
            param
            i: 样本的编号
            """
            
            G_i = self.compute_G(i);  # 计算这个样本的GE = G_i - self.train_label[i];
            return E;
        
        def gaussian_kernel_for_test(self, x):
            """
            用于计算预测样本的高斯核函数,使用样本特征作为输入
            param
            x: 输入样本
            return
            K: 预测样本与每个样本的结果向量
            """
            
            K = np.exp(-1 * np.sum((self.train_data - x)**2, axis = 1) / (2 * self.sigma**2));
            return K;
        
        def compute_G_for_test(self, x):
            """
            计算预测样本的G值
            param
            x: 输入样本
            """
            
            K_i = self.gaussian_kernel_for_test(x);  # 计算这个样本的高斯核结果
            G = np.sum(self.alpha * self.train_label * K_i) + self.b;
            return G;
        
        def judge_KKT(self, i):
            """
            判断第i个样本是否满足KKT
            return
            True: 满足KKT条件
            False: 不满足
            """
            
            Ei = self.compute_E(i);
            # 该语句用于判断是否满足3KTT条件
            if (((self.train_label[i] * Ei < -self.epsilon) and (self.alpha[i] < self.C)) or ((self.train_label[i] * Ei > self.epsilon) and (self.alpha[i] > 0))):
                return False;
            
            return True;
                
        
        def select_second_alpha(self, i):
            """
            选出第二个alpha
            param
            i: 选中的第1个alpha的编号
            return 
            j: 第二个alpha的索引
            """
            
            delta_Es = abs(self.E - self.E[i]);  # 计算第i个样本的E与所有的其他样本的E差
            delta_Es[i] = -1;  # 把与自己的差值设为负的,防止选到自己
            j = np.argmax(delta_Es);
            return j
    
        
        def update(self, i, j, E1, E2):
            """
            选择好两个alpha后,更新alpha,如果alpha变化太小则直接退出
            parame
            i: 第一个alpha的编号
            j: 第二个alpha的编号
            E1:1个alpha样本的EE2:2个alpha样本的Ereturn
            True: 成功更新
            False: 未进行更新,返回重新选择alpha
            """
            
            # 计算未经剪辑的alpha2的解
            x1, x2 = self.train_data[i], self.train_data[j];  # 选择的第1个和第2个alpha的样本
            y1, y2 = self.train_label[i], self.train_label[j];  # 选择的第1个和第2个alpha的样本标签
            alpha1, alpha2 = self.alpha[i], self.alpha[j];  # 选择的第1个和第2个alpha
            self.single_gaussian_kernel(i, j)
            K11, K12, K22 = self.single_gaussian_kernel(i, i), self.single_gaussian_kernel(i, j), self.single_gaussian_kernel(j, j);
            eta = K11 + K22 - 2 * K12;           
            alpha2_new_unc = self.alpha[j] + (self.train_label[j] * (E1 - E2) ) / eta;  # 未经剪辑的alpha2的解
            # 剪辑解
            if (y1 == y2):
                L = max(0, alpha1 + alpha2 - self.C);
                H = min(self.C, alpha1 + alpha2);
            else:
                L = max(0, alpha2 - alpha1);
                H = min(self.C, self.C + alpha2 - alpha1);
            if (alpha2_new_unc<=H and alpha2_new_unc>=L):
                alpha2_new = alpha2_new_unc;
            elif (alpha2_new_unc < L):
                alpha2_new = L;
            else:
                alpha2_new = H;     
            if (abs(alpha2_new - alpha2) < 0.00001):  # 如果更新太小,直接return,重新选择
                return False
            alpha1_new = alpha1 + y1 * y2 * (alpha2 - alpha2_new);
            self.alpha[i] = alpha1_new;  # 更新alpha1
            self.alpha[j] = alpha2_new;  # 更新alpha2
            # 更新b
            b1 = -1 * E1 - y1 * K11 * (alpha1_new - alpha1) - y2 * K12 * (alpha2_new - alpha2) + self.b;
            b2 = -1 * E2 - y1 * K12 * (alpha1_new - alpha1) - y2 * K22 * (alpha2_new - alpha2) + self.b;  
            # 确定b
            if (alpha1_new < self.C and alpha1_new > 0):
                self.b = b1;
            elif (alpha2_new < self.C and alpha2_new > 0):
                self.b = b2;
            else:
                self.b = (b1 + b2) / 2;
    
            self.E[i] = self.compute_E(i);  # 更新E1
            self.E[j] = self.compute_E(j);  # 更新E2
            return True;
        
        def train(self):
            """
            使用SMO算法进行训练
            """
            
            iter_time = 0;  # 当前的循环次数
            entire_flag = True;  # 是否进行整个数据集遍历的标记
            parameterChanged = 1;  # 记录参数改变的次数
            while (iter_time < self.iter_time and parameterChanged > 0 or entire_flag):
                parameterChanged = 0;
                if (entire_flag):
                    entire_flag = False;  # 下次对支持向量进行遍历
                    for i in range(self.m):  # 遍历每个样本,选择第1个alpha
                        if (not self.judge_KKT(i)):  # 如果这个样本不满足KKT条件,则作为第1个alpha,然后选择第2个alpha
                            self.E[i] = self.compute_E(i);  # 第1个alpha样本的E值
                            j = self.select_second_alpha(i);  # 选择第2个alpha
                            self.E[j] = self.compute_E(j);  # 第2E值
                            flag = self.update(i, j, self.E[i], self.E[j]); 
                            if (flag == True):
                                parameterChanged += 1;
                else:
                    indices_in = [];  # 存放支持向量0<alpha<C的索引
                    for i in range(self.m):
                        if (self.alpha[i]>0 and self.alpha[i]<self.C):
                            indices_in.append(i);
                            
                    for i in indices_in:  # 对支持向量先进行选择
                        if (not self.judge_KKT(i)):  # 如果这个样本不满足KKT,则作为第1个alpha,然后选择第2个alpha
                            self.E[i] = self.compute_E(i);  # 第1个alpha样本的E值
                            j = self.select_second_alpha(i);  # 选择第2个alpha
                            self.E[j] = self.compute_E(j);  # 第2E值
                            flag = self.update(i, j, self.E[i], self.E[j]); 
                            if (flag == True):
                                parameterChanged += 1;
                                
                    if (parameterChanged == 0):  # 如果参数1个都没改变,则接下来进行整个训练集的遍历,如果参数变了,继续遍历支持向量
                        entire_flag = True;
                        
                iter_time += 1;
                #打印迭代轮数,i值,该迭代轮数修改alpha数目
    #             print("iter: %d , pairs changed %d" % (iter_time, parameterChanged))
            #全部计算结束后,重新遍历一遍alpha,查找里面的支持向量
            for i in range(self.m):
                #如果alpha>0,说明是支持向量
                if (self.alpha[i] > 0 and self.alpha[i] < self.C):
                    #将支持向量的索引保存起来
                    self.supportVecIndex.append(i)
    
                    
        def sign(self, z):
            """
            决策函数,返回类别
            param
            z: 预测值
            """
            if (z >= 0):
                return 1;
            else:
                return -1;
            
        def show_trian_data(self):
            """
            打印原始数据
            """
            
            p = np.where(self.train_label==1)[0];  # 正样本索引
            n = np.where(self.train_label==-1)[0];  # 负样本索引  
            fig, ax = plt.subplots(figsize=(8, 6));
            ax.scatter(self.train_data[p, 0], self.train_data[p, 1],  color='r');
            ax.scatter(self.train_data[n, 0], self.train_data[n, 1],  color='b');
            plt.show();
            
        
        def show_support_vector(self):
            """
            打印支持向量
            """
            
            p = np.array(self.supportVecIndex)[np.where(self.train_label[self.supportVecIndex]==1)[0]];  # 正样本索引
            n = np.array(self.supportVecIndex)[np.where(self.train_label[self.supportVecIndex]==-1)[0]];  # 负样本索引  
            fig, ax = plt.subplots(figsize=(8, 6));
            ax.scatter(self.train_data[p, 0], self.train_data[p, 1],  color='r');
            ax.scatter(self.train_data[n, 0], self.train_data[n, 1],  color='b');
            plt.show();
        
        def show_boundary(self, flag):
            """
            打印决策边界
            param
            flag:1则是画出数据集1的决策边界,2则是画出数据集2的决策边界。
                  因为数据集2有噪声样本,直接取最大最小值作为边界范围就太大了。
            """
            
            if (flag == 1):
                x_left, x_right = np.min(train_data[:, 0]) - 0.05, np.max(train_data[:, 0]) + 0.05;  # 左右界
                y_low, y_high = np.min(train_data[:, 1]) - 0.05, np.max(train_data[:, 1]) + 0.05;  # 上下界
            elif (flag == 2):
                x_left, x_right = 0, 1.1;  # 左右界
                y_low, y_high = 0.38, 1;  # 上下界
            x = np.linspace(x_left, x_right, 500);  # 按左右界生成序列
            y = np.linspace(y_low, y_high, 500);  # 同上
            xx, yy = np.meshgrid(x, y);  # 生成网格数据
            xx = xx.reshape(-1, 1);  # 拉长
            yy = yy.reshape(-1, 1);
            test_data = np.column_stack((xx, yy));
            zz = [];  # 存放预测类别
            for sample in test_data:
                zz.append(self.sign(self.compute_G_for_test(sample)));  # 把预测类别添加到zz中
            
            zz = np.array(zz);
            p_sample = np.where(zz == 1)[0];
            n_sample = np.where(zz == -1)[0];   
            
            fig, ax = plt.subplots(figsize=(8, 6));
            ax.scatter(test_data[p_sample, 0], test_data[p_sample, 1],  color='r');
            ax.scatter(test_data[n_sample, 0], test_data[n_sample, 1],  color='b');  
            plt.show();
    
    
    
    """
    运行一个训练集实例
    """
    path = 'dataset_2.mat';  # 需要修改为自己的路径
    train_data, train_label = load_data(path):
    svm = SVM(train_data, train_label, sigma = 0.1, C = 200);
    svm.train();
    svm.show_boundary(2);  # 使用dataset_2时参数传2
    

    参考文献

    《统计学习方法》
    博客:参考代码1
    博客:参考代码2
    知乎:零基础学SVM
    B站:李航统计学习之SVM支持向量机+SMO算法数学推导

    展开全文
  • SVM 支持向量机python实现
  • 支持向量机SVM python代码 亲测可在pycharm用,可以用于统计学习方法的课后练习使用
  • 1 Support Vector Machines 1.1 Prepare datasets import numpy as np import pandas as pd import matplotlib.pyplot as plt ...from sklearn import svm ''' 1.Prepare datasets ''' mat = loadmat('data/e

    1 Support Vector Machines

    1.1 Prepare datasets

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import seaborn as sb    # 更好的可视化封装库
    from scipy.io import loadmat
    from sklearn import svm
    
    '''
    1.Prepare datasets
    '''
    mat = loadmat('data/ex6data1.mat')
    print(mat.keys())
    # dict_keys(['__header__', '__version__', '__globals__', 'X', 'y'])
    X = mat['X']
    y = mat['y']
    '''大多数SVM的库会自动帮你添加额外的特征x0,所以无需手动添加。'''
    
    def plotData(X, y):
        plt.figure(figsize=(8, 6))
        plt.scatter(X[:, 0], X[:, 1], c=y.flatten(), cmap='rainbow')
        # c=list,设置cmap,根据label不一样,设置不一样的颜色
        # c:色彩或颜色序列   camp:colormap(颜色表)
        plt.xlabel('x1')
        plt.ylabel('x2')
        # plt.legend()
        # plt.grid(True)
        # # plt.show()
        pass
    
    
    # plotData(X, y)
    

    image-20210602131137820

    接下来取一段范围,这段范围是根据已有数据的大小进行细微扩大,并且将其分成500段,通过meshgrid获得网格线,最终利用等高线图画出分界线

    1.2 Decision Boundary

    def plotBoundary(clf, X):
        '''Plot Decision Boundary'''
        x_min, x_max = X[:, 0].min() * 1.2, X[:, 0].max() * 1.1
        y_min, y_max = X[:, 1].min() * 1.1, X[:, 1].max() * 1.1
        # np.linspace(x_min, x_max, 500).shape---->(500, )  500是样本数
        # xx.shape, yy.shape ---->(500, 500) (500, 500)
        xx, yy = np.meshgrid(np.linspace(x_min, x_max, 500), np.linspace(y_min, y_max, 500))
        Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
        # model.predict:模型预测 (250000, )
        # ravel()将多维数组转换为一维数组 xx.ravel().shape ----> (250000,1)
        # np.c 中的c是column(列)的缩写,就是按列叠加两个矩阵,就是把两个矩阵左右组合,要求行数相等。
        # np.c_[xx.ravel(), yy.ravel()].shape ----> (250000,2) 就是说建立了250000个样本
        Z = Z.reshape(xx.shape)
        plt.contour(xx, yy, Z)
        # 等高线得作用就是画出分隔得线
        pass
    

    通过调用sklearn中支持向量机的代码,来进行模型的拟合

    models = [svm.SVC(C, kernel='linear') for C in [1, 100]]
    # 支持向量机模型 (kernel:核函数选项,这里是线性核函数 , C:权重,这里取1和100)
    # 线性核函数画的决策边界就是直线
    clfs = [model.fit(X, y.ravel()) for model in models]    # model.fit:拟合出模型
    score = [model.score(X, y) for model in models]        # [0.9803921568627451, 1.0]
    # title = ['SVM Decision Boundary with C = {}(Example Dataset 1)'.format(C) for C in [1, 100]]
    
    def plot():
        title = ['SVM Decision Boundary with C = {}(Example Dataset 1)'.format(C) for C in [1, 100]]
        for model, title in zip(clfs, title):
            # zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
            plt.figure(figsize=(8, 5))
            plotData(X, y)
            plotBoundary(model, X)  # 用拟合好的模型(预测那些250000个样本),绘制决策边界
            plt.title(title)
            pass
        pass
    # plt.show()
    

    image-20210601170724577

    image-20210601170741687

    A large C parameter tells the SVM to try to classify all the examples correctly.

    C plays a rolesimilar to λ, where λ is the regularization parameter that we were using previously for logistic regression.

    可以理解对误差的惩罚,惩罚大,则曲线分类精准。

    1.2 SVM with Gaussian Kernels

    当用SVM作非线性分类时,我们一般使用Gaussian Kernels。
    K gaussian  ( x ( i ) , x ( j ) ) = exp ⁡ ( − ∥ x ( i ) − x ( j ) ∥ 2 2 σ 2 ) = exp ⁡ ( − ∑ k = 1 ( x k ( i ) − x k ( j ) ) 2 2 σ 2 ) K_{\text {gaussian }}\left(x^{(i)}, x^{(j)}\right)=\exp \left(-\frac{\left\|x^{(i)}-x^{(j)}\right\|^{2}}{2 \sigma^{2}}\right)=\exp \left(-\frac{\sum_{k=1}\left(x_{k}^{(i)}-x_{k}^{(j)}\right)^{2}}{2 \sigma^{2}}\right) Kgaussian (x(i),x(j))=exp(2σ2x(i)x(j)2)=exp2σ2k=1(xk(i)xk(j))2
    本文中使用其自带的即可。

    def gaussKernel(x1, x2, sigma):
        return np.exp(-(x1 - x2) ** 2).sum() / (2 * sigma ** 2)
    
    
    a = gaussKernel(np.array([1, 2, 1]), np.array([0, 4, -1]), 2.)  # 0.32465246735834974
    # print(a)
    
    1.2.1 Gaussian Kernel-Example Dataset2
    mat = loadmat('data/ex6data2.mat')
    x2 = mat['X']
    y2 = mat['y']
    plotData(x2, y2)
    plt.show()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ktLdbJ8u-1622612399587)(C:/Users/DELL/AppData/Roaming/Typora/typora-user-images/image-20210601172524887.png)]

    sigma = 0.1
    gamma = np.power(sigma, -2)/2
    '''
    高斯核函数中的gamma越大,相当高斯函数中的σ越小,此时的分布曲线也就会越高越瘦。
    高斯核函数中的gamma越小,相当高斯函数中的σ越大,此时的分布曲线也就越矮越胖,smoothly,higher bias, lower variance
    '''
    clf = svm.SVC(C=1, kernel='rbf', gamma=gamma)
    model = clf.fit(x2, y2.flatten())       # kernel='rbf'表示支持向量机使用高斯核函数
    # https://blog.csdn.net/guanyuqiu/article/details/85109441
    # plotData(x2, y2)
    # plotBoundary(model, x2)
    # plt.show()
    

    image-20210601193750755

    1.2.2 Gaussian Kernel-Example Dataset3
    '''
    Example Dataset3
    '''
    mat3 = loadmat('data/ex6data3.mat')
    x3, y3 = mat3['X'], mat3['y']
    Xval, yval = mat3['Xval'], mat3['yval']
    plotData(x3, y3)
    # plt.show()
    
    Cvalues = (0.01, 0.03, 0.1, 0.3, 1., 3., 10., 30.)  # 权重C的候选值
    sigmavalues = Cvalues   # 核函数参数的候选值
    best_pair, best_score = (0, 0), 0        # 最佳的(C,sigma)权值 ,决定系数(R2)
    # 寻找最佳的权值(C,sigma)
    for C in Cvalues:
        for sigma in sigmavalues:
            gamma = np.power(sigma, -2.) / 2
            model = svm.SVC(C=C, kernel='rbf', gamma=gamma)     # 使用核函数的支持向量机
            model.fit(x3, y3.flatten())      # 拟合出模型
            this_score = model.score(Xval, yval)        # 利用交叉验证集来选择最合适的权重
            '''
             model.score函数的返回值是决定系数,也称R2。
             可以测度回归直线对样本数据的拟合程度,决定系数的取值在0到1之间,
             决定系数越高,模型的拟合效果越好,即模型解释因变量的能力越强。
             '''
            # 选择拟合得最好得权重值
            if this_score > best_score:
                best_score = this_score
                best_pair = (C, sigma)
            pass
        pass
    print('最优(C, sigma)权值:', best_pair, '决定系数:', best_score)
    # 最优(C, sigma)权值: (1.0, 0.1) 决定系数: 0.965
    model = svm.SVC(1, kernel='rbf', gamma=np.power(0.1, -2.) / 2)
    # 用确定好的权重再重新声明一次支持向量机
    model.fit(x3, y3.flatten())
    plotData(x3, y3)
    plotBoundary(model, x3)
    # plt.show()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zODc0dOu-1622612399590)(C:/Users/DELL/AppData/Roaming/Typora/typora-user-images/image-20210601224239696.png)]

    SVM中的score的作用:

    img

    2 Spam Classfication

    邮件分类这一块就偷一下懒拉,给大家看看代码

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.io import loadmat
    from sklearn import svm
    import pandas as pd
    import re  # regular expression for e-mail processing
    
    # 这是一个可用的英文分词算法(Porter stemmer)
    from stemming.porter2 import stem
    
    # 这个英文算法似乎更符合作业里面所用的代码,与上面效果差不多
    import nltk, nltk.stem.porter
    
    with open('data/emailSample1.txt', 'r') as f:
        email = f.read()
        pass
    print(email)
    #   我们可以做如下处理:
    #   1. Lower-casing: 把整封邮件转化为小写。
    #   2. Stripping HTML: 移除所有HTML标签,只保留内容。
    #   3. Normalizing URLs: 将所有的URL替换为字符串 “httpaddr”.
    #   4. Normalizing Email Addresses: 所有的地址替换为 “emailaddr”
    #   5. Normalizing Dollars: 所有dollar符号($)替换为“dollar”.
    #   6. Normalizing Numbers: 所有数字替换为“number”
    #   7. Word Stemming(词干提取): 将所有单词还原为词源。
    #   例如,“discount”, “discounts”, “discounted” and “discounting”都替换为“discount”。
    #   8. Removal of non-words: 移除所有非文字类型,所有的空格(tabs, newlines, spaces)调整为一个空格.
    
    
    def processEmail(email):
        '''除了Word Stemming, Removal of non-words之外所有的操作'''
        email = email.lower()
        email = re.sub('<[^<>]>', '', email)    # 匹配<开头,然后所有不是< ,> 的内容,知道>结尾,相当于匹配<...>
        email = re.sub('(http|https)://[^\s]*', 'httpaddr', email)  # 匹配//后面不是空白字符的内容,遇到空白字符则停止
        email = re.sub('[^\s]+@[^\s]+', 'emailaddr', email)
        email = re.sub('[\$]+', 'dollar', email)
        email = re.sub('[\d]+', 'number', email)
        return email
    
    
    def email2TokenList(email):
        """预处理数据,返回一个干净的单词列表"""
    
        # I'll use the NLTK stemmer because it more accurately duplicates the
        # performance of the OCTAVE implementation in the assignment
        stemmer = nltk.stem.porter.PorterStemmer()
    
        email = processEmail(email)
    
        # 将邮件分割为单个单词,re.split() 可以设置多种分隔符
        tokens = re.split('[ \@\$\/\#\.\-\:\&\*\+\=\[\]\?\!\(\)\{\}\,\'\"\>\_\<\;\%]', email)
    
        # 遍历每个分割出来的内容
        tokenlist = []
        for token in tokens:
            # 删除任何非字母数字的字符
            token = re.sub('[^a-zA-Z0-9]', '', token)
            # Use the Porter stemmer to 提取词根
            stemmed = stemmer.stem(token)
            # 去除空字符串‘’,里面不含任何字符
            if not len(token):
                continue
            tokenlist.append(stemmed)
    
        return tokenlist
    
    # 在对邮件进行预处理之后,我们有一个处理后的单词列表。
    # 下一步是选择我们想在分类器中使用哪些词,我们需要去除哪些词。
    # 我们有一个词汇表vocab.txt,里面存储了在实际中经常使用的单词,共1899个。
    # 我们要算出处理后的email中含有多少vocab.txt中的单词,并返回在vocab.txt中的index,
    # 这就我们想要的训练单词的索引。
    
    
    def email2VocanIndices(email, vocab):
        '''提取存在单词的索引'''
        token = email2TokenList(email)
        index = [i for i in range(len(vocab)) if vocab[i] in token]
        return index
    
    
    def email2FeatureVector(email):
        '''
        将email转化为词向量,n是vocab的长度。存在单词的相应位置的值置为1,其余为0
        :param email:
        :return:
        '''
        df = pd.read_table('data/vocab.txt', names=['words'])
        vocab = np.array(df)    # return array
        vector = np.zeros(len(vocab))   # init vector
        vocab_indices = email2VocanIndices(email, vocab)    # 返回含有单词的索引
        # 将有单词的索引值置为1
        for i in vocab_indices:
            vector[i] = 1
            pass
        return vector
    
    
    vector = email2FeatureVector(email)
    print('length of vector = {}\nnum of non-zero = {}'.format(len(vector), int(vector.sum())))
    
    
    # Training set
    mat1 = loadmat('data/spamTrain.mat')
    X, y = mat1['X'], mat1['y']
    
    # Test set
    mat2 = loadmat('data/spamTest.mat')
    Xtest, ytest = mat2['Xtest'], mat2['ytest']
    
    clf = svm.SVC(C=0.1, kernel='linear')
    clf.fit(X, y)
    
    
    predTrain = clf.score(X, y)
    predTest = clf.score(Xtest, ytest)
    print(predTrain, predTest)
    # 0.99825 
    

    image-20210602083108216

    image-20210602091043923

    附完整代码:

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import seaborn as sb    # 更好的可视化封装库
    from scipy.io import loadmat
    from sklearn import svm
    
    '''
    1.Prepare datasets
    '''
    mat = loadmat('data/ex6data1.mat')
    print(mat.keys())
    # dict_keys(['__header__', '__version__', '__globals__', 'X', 'y'])
    X = mat['X']
    y = mat['y']
    '''大多数SVM的库会自动帮你添加额外的特征x0,所以无需手动添加。'''
    
    
    def plotData(X, y):
        plt.figure(figsize=(8, 6))
        plt.scatter(X[:, 0], X[:, 1], c=y.flatten(), cmap='rainbow')
        # c=list,设置cmap,根据label不一样,设置不一样的颜色
        # c:色彩或颜色序列   camp:colormap(颜色表)
        plt.xlabel('x1')
        plt.ylabel('x2')
        # plt.legend()
        # plt.grid(True)
        # # plt.show()
        pass
    
    
    # plotData(X, y)
    def plotBoundary(clf, X):
        '''Plot Decision Boundary'''
        x_min, x_max = X[:, 0].min() * 1.2, X[:, 0].max() * 1.1
        y_min, y_max = X[:, 1].min() * 1.1, X[:, 1].max() * 1.1
        # np.linspace(x_min, x_max, 500).shape---->(500, )  500是样本数
        # xx.shape, yy.shape ---->(500, 500) (500, 500)
        xx, yy = np.meshgrid(np.linspace(x_min, x_max, 500), np.linspace(y_min, y_max, 500))
        Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
        # model.predict:模型预测 (250000, )
        # ravel()将多维数组转换为一维数组 xx.ravel().shape ----> (250000,1)
        # np.c 中的c是column(列)的缩写,就是按列叠加两个矩阵,就是把两个矩阵左右组合,要求行数相等。
        # np.c_[xx.ravel(), yy.ravel()].shape ----> (250000,2) 就是说建立了250000个样本
        Z = Z.reshape(xx.shape)
        plt.contour(xx, yy, Z)
        # 等高线得作用就是画出分隔得线
        pass
    
    
    models = [svm.SVC(C, kernel='linear') for C in [1, 100]]
    # 支持向量机模型 (kernel:核函数选项,这里是线性核函数 , C:权重,这里取1和100)
    # 线性核函数画的决策边界就是直线
    clfs = [model.fit(X, y.ravel()) for model in models]    # model.fit:拟合出模型
    score = [model.score(X, y) for model in models]        # [0.9803921568627451, 1.0]
    # title = ['SVM Decision Boundary with C = {}(Example Dataset 1)'.format(C) for C in [1, 100]]
    
    def plot():
        title = ['SVM Decision Boundary with C = {}(Example Dataset 1)'.format(C) for C in [1, 100]]
        for model, title in zip(clfs, title):
            # zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
            plt.figure(figsize=(8, 5))
            plotData(X, y)
            plotBoundary(model, X)  # 用拟合好的模型(预测那些250000个样本),绘制决策边界
            plt.title(title)
            pass
        pass
    
    # plt.show()
    
    '''
    2.SVM with Gaussian Kernels
    '''
    
    
    def gaussKernel(x1, x2, sigma):
        return np.exp(-(x1 - x2) ** 2).sum() / (2 * sigma ** 2)
    
    
    a = gaussKernel(np.array([1, 2, 1]), np.array([0, 4, -1]), 2.)  # 0.32465246735834974
    # print(a)
    
    '''
    Example Dataset 2
    '''
    
    mat = loadmat('data/ex6data2.mat')
    x2 = mat['X']
    y2 = mat['y']
    plotData(x2, y2)
    plt.show()
    
    sigma = 0.1
    gamma = np.power(sigma, -2)/2
    '''
    高斯核函数中的gamma越大,相当高斯函数中的σ越小,此时的分布曲线也就会越高越瘦。
    高斯核函数中的gamma越小,相当高斯函数中的σ越大,此时的分布曲线也就越矮越胖,smoothly,higher bias, lower variance
    '''
    clf = svm.SVC(C=1, kernel='rbf', gamma=gamma)
    model = clf.fit(x2, y2.flatten())       # kernel='rbf'表示支持向量机使用高斯核函数
    # https://blog.csdn.net/guanyuqiu/article/details/85109441
    # plotData(x2, y2)
    # plotBoundary(model, x2)
    # plt.show()
    
    
    '''
    Example Dataset3
    '''
    mat3 = loadmat('data/ex6data3.mat')
    x3, y3 = mat3['X'], mat3['y']
    Xval, yval = mat3['Xval'], mat3['yval']
    plotData(x3, y3)
    # plt.show()
    
    Cvalues = (0.01, 0.03, 0.1, 0.3, 1., 3., 10., 30.)  # 权重C的候选值
    sigmavalues = Cvalues   # 核函数参数的候选值
    best_pair, best_score = (0, 0), 0        # 最佳的(C,sigma)权值 ,决定系数(R2)
    # 寻找最佳的权值(C,sigma)
    for C in Cvalues:
        for sigma in sigmavalues:
            gamma = np.power(sigma, -2.) / 2
            model = svm.SVC(C=C, kernel='rbf', gamma=gamma)     # 使用核函数的支持向量机
            model.fit(x3, y3.flatten())      # 拟合出模型
            this_score = model.score(Xval, yval)        # 利用交叉验证集来选择最合适的权重
            '''
             model.score函数的返回值是决定系数,也称R2。
             可以测度回归直线对样本数据的拟合程度,决定系数的取值在0到1之间,
             决定系数越高,模型的拟合效果越好,即模型解释因变量的能力越强。
             '''
            # 选择拟合得最好得权重值
            if this_score > best_score:
                best_score = this_score
                best_pair = (C, sigma)
            pass
        pass
    print('最优(C, sigma)权值:', best_pair, '决定系数:', best_score)
    # 最优(C, sigma)权值: (1.0, 0.1) 决定系数: 0.965
    model = svm.SVC(1, kernel='rbf', gamma=np.power(0.1, -2.) / 2)
    # 用确定好的权重再重新声明一次支持向量机
    model.fit(x3, y3.flatten())
    plotData(x3, y3)
    plotBoundary(model, x3)
    # plt.show()
    

    参考链接:https://blog.csdn.net/Cowry5/article/details/80465922

    展开全文
  • 除了在Matlab中使用PRTools工具箱中的svm算法,Python中一样可以使用支持向量机做分类。因为Python中的sklearn库也集成了SVM算法,本文的运行环境是Pycharm。 一、导入sklearn算法包 Scikit-Learn库已经实现了所有...
  • 支持向量机,能在N维平面中,找到最明显得对数据进行分类的一个超平面!看下面这幅图: 如上图中,在二维平面中,有红和蓝两类点。要对这两类点进行分类,可以有很多种分类方法,就如同图中多条绿线,都
  • 主要介绍了Python SVM(支持向量机)实现方法,结合完整实例形式分析了基于Python实现向量机SVM算法的具体步骤与相关操作注意事项,需要的朋友可以参考下
  • SVM支持向量机是建立于统计学习理论上的一种分类算法,适合与处理具备高维特征的数据集。 SVM算法的数学原理相对比较复杂,好在由于SVM算法的研究与应用如此火爆,CSDN博客里也有大量的好文章对此进行分析,下面给出...
  • python利用支持向量机SVM进行时间序列预测, 包括数据和python代码 python利用支持向量机SVM进行时间序列预测, 包括数据和python代码
  • 使用python手动实现了SVM支持向量机,包括其中二次规划的求解(调用cvxopt包),实现了软间隔及核技术,以及对数据集及分类效果的可视化!建议配合我的SVM PPT一起学习SVM 不是直接调用sklearn的SVM!!
  • 主要介绍了Python 支持向量机分类器的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • SVM手写数字识别,使用scikit-learn库的数据库
  • 支持向量机SVM通俗理解(python代码实现)

    万次阅读 多人点赞 2017-05-11 02:42:08
    第三次,也就是这次通过python代码手动来实现SVM,才让我突然对SVM不有畏惧感。希望这里我能通过简单粗暴的文字,能让读者理解到底什么是SVM,这货的算法思想是怎么样的。看之前千万不要畏惧,说到底就...

    这是第三次来“复习”SVM了,第一次是使用SVM包,调用包并尝试调节参数。听闻了“流弊”SVM的算法。第二次学习理论,看了李航的《统计学习方法》以及网上的博客。看完后感觉,满满的公式。。。记不住啊。第三次,也就是这次通过python代码手动来实现SVM,才让我突然对SVM不有畏惧感。希望这里我能通过简单粗暴的文字,能让读者理解到底什么是SVM,这货的算法思想是怎么样的。看之前千万不要畏惧,说到底就是个算法,每天啃一点,总能啃完它,慢慢来还可以加深印象。
    SVM是用来解决分类问题的,如果解决两个变量的分类问题,可以理解成用一条直线把点给分开,完成分类。如下:
    这里写图片描述
    上面这些点很明显不一样,我们从中间画一条直线就可以用来分割这些点,但是什么样的直线才是最好的呢?通俗的说,就是一条直线“最能”分割这些点,也就是上图中的直线。他是最好的一条直线,使所有的点都“尽量”远离中间那条直线。总得的来说,SVM就是为了找出一条分割的效果最好的直线。怎么样找出这条直线,就变成了一个数学问题,通过数学一步一步的推导,最后转化成程序。这里举例是二个特征的分类问题,如果有三个特征,分类线就变成了分类平面,多个特征的话就变成了超平面。从这个角度出发去看待SVM,会比较轻松。

    数学解决方法大致如下:
    目的是求最大分隔平面,也就是选取靠近平面最近的点,使这些点到分隔平面的距离W最大,是一个典型的凸二次规划问题。
    这里写图片描述
    但是上面需要求解两个参数w和b;于是为求解这个问题,把二次规划问题转换为对偶问题
    这里写图片描述
    这样就只需求一个参数a了,通过SMO算法求出a后,再计算出b
    这里写图片描述
    最后通过f(x)用做预测。

    详细的数学推导,请看下面两个博客以及《统计学习方法》,这两位博主其实已经讲解的非常详细了。
    http://blog.csdn.net/zouxy09/article/details/17291543
    http://blog.csdn.net/v_july_v/article/details/7624837
    《统计学习方法》这本书里面全是数学公式,非常“课本”,建议先看博客,有个大概印象再去看“课本”,跟着“课本”一步一步的推导。最后用python代码实现一遍,应该就可以拿下SVM了。

    python代码实现可以加深对那些数学推导公式的印象,看公式的时候,可能会想,这些推导好复杂,都有些什么用啊,结果写代码的时候会发现,原来最后都用在代码里。所以写代码可以加深对SVM的理解。
    下面是SVM的python代码实现,我做了详细的注释,刚开始看代码也会觉得好长好复杂,慢慢看后发现,代码就是照着SVM的数学推导,把最后的公式推导转化为代码和程序的逻辑,代码本身并不复杂。

    from numpy import * 
    
    def loadDataSet(filename): #读取数据
        dataMat=[]
        labelMat=[]
        fr=open(filename)
        for line in fr.readlines():
            lineArr=line.strip().split('\t')
            dataMat.append([float(lineArr[0]),float(lineArr[1])])
            labelMat.append(float(lineArr[2]))
        return dataMat,labelMat #返回数据特征和数据类别
    
    def selectJrand(i,m): #在0-m中随机选择一个不是i的整数
        j=i
        while (j==i):
            j=int(random.uniform(0,m))
        return j
    
    def clipAlpha(aj,H,L):  #保证a在L和H范围内(L <= a <= H)
        if aj>H:
            aj=H
        if L>aj:
            aj=L
        return aj
    
    def kernelTrans(X, A, kTup): #核函数,输入参数,X:支持向量的特征树;A:某一行特征数据;kTup:('lin',k1)核函数的类型和参数
        m,n = shape(X)
        K = mat(zeros((m,1)))
        if kTup[0]=='lin': #线性函数
            K = X * A.T
        elif kTup[0]=='rbf': # 径向基函数(radial bias function)
            for j in range(m):
                deltaRow = X[j,:] - A
                K[j] = deltaRow*deltaRow.T
            K = exp(K/(-1*kTup[1]**2)) #返回生成的结果
        else:
            raise NameError('Houston We Have a Problem -- That Kernel is not recognized')
        return K
    
    
    #定义类,方便存储数据
    class optStruct:
        def __init__(self,dataMatIn, classLabels, C, toler, kTup):  # 存储各类参数
            self.X = dataMatIn  #数据特征
            self.labelMat = classLabels #数据类别
            self.C = C #软间隔参数C,参数越大,非线性拟合能力越强
            self.tol = toler #停止阀值
            self.m = shape(dataMatIn)[0] #数据行数
            self.alphas = mat(zeros((self.m,1)))
            self.b = 0 #初始设为0
            self.eCache = mat(zeros((self.m,2))) #缓存
            self.K = mat(zeros((self.m,self.m))) #核函数的计算结果
            for i in range(self.m):
                self.K[:,i] = kernelTrans(self.X, self.X[i,:], kTup)
    
    
    def calcEk(oS, k): #计算Ek(参考《统计学习方法》p127公式7.105)
        fXk = float(multiply(oS.alphas,oS.labelMat).T*oS.K[:,k] + oS.b)
        Ek = fXk - float(oS.labelMat[k])
        return Ek
    
    #随机选取aj,并返回其E值
    def selectJ(i, oS, Ei):
        maxK = -1
        maxDeltaE = 0
        Ej = 0
        oS.eCache[i] = [1,Ei]
        validEcacheList = nonzero(oS.eCache[:,0].A)[0]  #返回矩阵中的非零位置的行数
        if (len(validEcacheList)) > 1:
            for k in validEcacheList:
                if k == i:
                    continue
                Ek = calcEk(oS, k)
                deltaE = abs(Ei - Ek)
                if (deltaE > maxDeltaE): #返回步长最大的aj
                    maxK = k
                    maxDeltaE = deltaE
                    Ej = Ek
            return maxK, Ej
        else:
            j = selectJrand(i, oS.m)
            Ej = calcEk(oS, j)
        return j, Ej
    
    
    def updateEk(oS, k): #更新os数据
        Ek = calcEk(oS, k)
        oS.eCache[k] = [1,Ek]
    
    #首先检验ai是否满足KKT条件,如果不满足,随机选择aj进行优化,更新ai,aj,b值
    def innerL(i, oS): #输入参数i和所有参数数据
        Ei = calcEk(oS, i) #计算E值
        if ((oS.labelMat[i]*Ei < -oS.tol) and (oS.alphas[i] < oS.C)) or ((oS.labelMat[i]*Ei > oS.tol) and (oS.alphas[i] > 0)): #检验这行数据是否符合KKT条件 参考《统计学习方法》p128公式7.111-113
            j,Ej = selectJ(i, oS, Ei) #随机选取aj,并返回其E值
            alphaIold = oS.alphas[i].copy()
            alphaJold = oS.alphas[j].copy()
            if (oS.labelMat[i] != oS.labelMat[j]): #以下代码的公式参考《统计学习方法》p126
                L = max(0, oS.alphas[j] - oS.alphas[i])
                H = min(oS.C, oS.C + oS.alphas[j] - oS.alphas[i])
            else:
                L = max(0, oS.alphas[j] + oS.alphas[i] - oS.C)
                H = min(oS.C, oS.alphas[j] + oS.alphas[i])
            if L==H:
                print("L==H")
                return 0
            eta = 2.0 * oS.K[i,j] - oS.K[i,i] - oS.K[j,j] #参考《统计学习方法》p127公式7.107
            if eta >= 0:
                print("eta>=0")
                return 0
            oS.alphas[j] -= oS.labelMat[j]*(Ei - Ej)/eta #参考《统计学习方法》p127公式7.106
            oS.alphas[j] = clipAlpha(oS.alphas[j],H,L) #参考《统计学习方法》p127公式7.108
            updateEk(oS, j)
            if (abs(oS.alphas[j] - alphaJold) < oS.tol): #alpha变化大小阀值(自己设定)
                print("j not moving enough")
                return 0
            oS.alphas[i] += oS.labelMat[j]*oS.labelMat[i]*(alphaJold - oS.alphas[j])#参考《统计学习方法》p127公式7.109
            updateEk(oS, i) #更新数据
            #以下求解b的过程,参考《统计学习方法》p129公式7.114-7.116
            b1 = oS.b - Ei- oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.K[i,i] - oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.K[i,j]
            b2 = oS.b - Ej- oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.K[i,j]- oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.K[j,j]
            if (0 < oS.alphas[i]<oS.C):
                oS.b = b1
            elif (0 < oS.alphas[j]<oS.C):
                oS.b = b2
            else:
                oS.b = (b1 + b2)/2.0
            return 1
        else:
            return 0
    
    
    #SMO函数,用于快速求解出alpha
    def smoP(dataMatIn, classLabels, C, toler, maxIter,kTup=('lin', 0)): #输入参数:数据特征,数据类别,参数C,阀值toler,最大迭代次数,核函数(默认线性核)
        oS = optStruct(mat(dataMatIn),mat(classLabels).transpose(),C,toler, kTup)
        iter = 0
        entireSet = True
        alphaPairsChanged = 0
        while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)):
            alphaPairsChanged = 0
            if entireSet:
                for i in range(oS.m): #遍历所有数据
                    alphaPairsChanged += innerL(i,oS)
                    print("fullSet, iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged)) #显示第多少次迭代,那行特征数据使alpha发生了改变,这次改变了多少次alpha
                iter += 1
            else:
                nonBoundIs = nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0]
                for i in nonBoundIs: #遍历非边界的数据
                    alphaPairsChanged += innerL(i,oS)
                    print("non-bound, iter: %d i:%d, pairs changed %d" % (iter,i,alphaPairsChanged))
                iter += 1
            if entireSet:
                entireSet = False
            elif (alphaPairsChanged == 0):
                entireSet = True
            print("iteration number: %d" % iter)
        return oS.b,oS.alphas
    
    def testRbf(data_train,data_test):
        dataArr,labelArr = loadDataSet(data_train) #读取训练数据
        b,alphas = smoP(dataArr, labelArr, 200, 0.0001, 10000, ('rbf', 1.3)) #通过SMO算法得到b和alpha
        datMat=mat(dataArr)
        labelMat = mat(labelArr).transpose()
        svInd=nonzero(alphas)[0]  #选取不为0数据的行数(也就是支持向量)
        sVs=datMat[svInd] #支持向量的特征数据
        labelSV = labelMat[svInd] #支持向量的类别(1或-1)
        print("there are %d Support Vectors" % shape(sVs)[0]) #打印出共有多少的支持向量
        m,n = shape(datMat) #训练数据的行列数
        errorCount = 0
        for i in range(m):
            kernelEval = kernelTrans(sVs,datMat[i,:],('rbf', 1.3)) #将支持向量转化为核函数
            predict=kernelEval.T * multiply(labelSV,alphas[svInd]) + b  #这一行的预测结果(代码来源于《统计学习方法》p133里面最后用于预测的公式)注意最后确定的分离平面只有那些支持向量决定。
            if sign(predict)!=sign(labelArr[i]): #sign函数 -1 if x < 0, 0 if x==0, 1 if x > 0
                errorCount += 1
        print("the training error rate is: %f" % (float(errorCount)/m)) #打印出错误率
        dataArr_test,labelArr_test = loadDataSet(data_test) #读取测试数据
        errorCount_test = 0
        datMat_test=mat(dataArr_test)
        labelMat = mat(labelArr_test).transpose()
        m,n = shape(datMat_test)
        for i in range(m): #在测试数据上检验错误率
            kernelEval = kernelTrans(sVs,datMat_test[i,:],('rbf', 1.3))
            predict=kernelEval.T * multiply(labelSV,alphas[svInd]) + b
            if sign(predict)!=sign(labelArr_test[i]):
                errorCount_test += 1
        print("the test error rate is: %f" % (float(errorCount_test)/m))
    
    #主程序
    def main():
        filename_traindata='C:\\Users\\Administrator\\Desktop\\data\\traindata.txt'
        filename_testdata='C:\\Users\\Administrator\\Desktop\\data\\testdata.txt'
        testRbf(filename_traindata,filename_testdata)
    
    if __name__=='__main__':
        main()

    样例数据如下:
    这里写图片描述
    训练数据:train_data

    -0.214824   0.662756    -1.000000
    -0.061569   -0.091875   1.000000
    0.406933    0.648055    -1.000000
    0.223650    0.130142    1.000000
    0.231317    0.766906    -1.000000
    -0.748800   -0.531637   -1.000000
    -0.557789   0.375797    -1.000000
    0.207123    -0.019463   1.000000
    0.286462    0.719470    -1.000000
    0.195300    -0.179039   1.000000
    -0.152696   -0.153030   1.000000
    0.384471    0.653336    -1.000000
    -0.117280   -0.153217   1.000000
    -0.238076   0.000583    1.000000
    -0.413576   0.145681    1.000000
    0.490767    -0.680029   -1.000000
    0.199894    -0.199381   1.000000
    -0.356048   0.537960    -1.000000
    -0.392868   -0.125261   1.000000
    0.353588    -0.070617   1.000000
    0.020984    0.925720    -1.000000
    -0.475167   -0.346247   -1.000000
    0.074952    0.042783    1.000000
    0.394164    -0.058217   1.000000
    0.663418    0.436525    -1.000000
    0.402158    0.577744    -1.000000
    -0.449349   -0.038074   1.000000
    0.619080    -0.088188   -1.000000
    0.268066    -0.071621   1.000000
    -0.015165   0.359326    1.000000
    0.539368    -0.374972   -1.000000
    -0.319153   0.629673    -1.000000
    0.694424    0.641180    -1.000000
    0.079522    0.193198    1.000000
    0.253289    -0.285861   1.000000
    -0.035558   -0.010086   1.000000
    -0.403483   0.474466    -1.000000
    -0.034312   0.995685    -1.000000
    -0.590657   0.438051    -1.000000
    -0.098871   -0.023953   1.000000
    -0.250001   0.141621    1.000000
    -0.012998   0.525985    -1.000000
    0.153738    0.491531    -1.000000
    0.388215    -0.656567   -1.000000
    0.049008    0.013499    1.000000
    0.068286    0.392741    1.000000
    0.747800    -0.066630   -1.000000
    0.004621    -0.042932   1.000000
    -0.701600   0.190983    -1.000000
    0.055413    -0.024380   1.000000
    0.035398    -0.333682   1.000000
    0.211795    0.024689    1.000000
    -0.045677   0.172907    1.000000
    0.595222    0.209570    -1.000000
    0.229465    0.250409    1.000000
    -0.089293   0.068198    1.000000
    0.384300    -0.176570   1.000000
    0.834912    -0.110321   -1.000000
    -0.307768   0.503038    -1.000000
    -0.777063   -0.348066   -1.000000
    0.017390    0.152441    1.000000
    -0.293382   -0.139778   1.000000
    -0.203272   0.286855    1.000000
    0.957812    -0.152444   -1.000000
    0.004609    -0.070617   1.000000
    -0.755431   0.096711    -1.000000
    -0.526487   0.547282    -1.000000
    -0.246873   0.833713    -1.000000
    0.185639    -0.066162   1.000000
    0.851934    0.456603    -1.000000
    -0.827912   0.117122    -1.000000
    0.233512    -0.106274   1.000000
    0.583671    -0.709033   -1.000000
    -0.487023   0.625140    -1.000000
    -0.448939   0.176725    1.000000
    0.155907    -0.166371   1.000000
    0.334204    0.381237    -1.000000
    0.081536    -0.106212   1.000000
    0.227222    0.527437    -1.000000
    0.759290    0.330720    -1.000000
    0.204177    -0.023516   1.000000
    0.577939    0.403784    -1.000000
    -0.568534   0.442948    -1.000000
    -0.011520   0.021165    1.000000
    0.875720    0.422476    -1.000000
    0.297885    -0.632874   -1.000000
    -0.015821   0.031226    1.000000
    0.541359    -0.205969   -1.000000
    -0.689946   -0.508674   -1.000000
    -0.343049   0.841653    -1.000000
    0.523902    -0.436156   -1.000000
    0.249281    -0.711840   -1.000000
    0.193449    0.574598    -1.000000
    -0.257542   -0.753885   -1.000000
    -0.021605   0.158080    1.000000
    0.601559    -0.727041   -1.000000
    -0.791603   0.095651    -1.000000
    -0.908298   -0.053376   -1.000000
    0.122020    0.850966    -1.000000
    -0.725568   -0.292022   -1.000000
    

    测试数据:test_data

    0.676771    -0.486687   -1.000000
    0.008473    0.186070    1.000000
    -0.727789   0.594062    -1.000000
    0.112367    0.287852    1.000000
    0.383633    -0.038068   1.000000
    -0.927138   -0.032633   -1.000000
    -0.842803   -0.423115   -1.000000
    -0.003677   -0.367338   1.000000
    0.443211    -0.698469   -1.000000
    -0.473835   0.005233    1.000000
    0.616741    0.590841    -1.000000
    0.557463    -0.373461   -1.000000
    -0.498535   -0.223231   -1.000000
    -0.246744   0.276413    1.000000
    -0.761980   -0.244188   -1.000000
    0.641594    -0.479861   -1.000000
    -0.659140   0.529830    -1.000000
    -0.054873   -0.238900   1.000000
    -0.089644   -0.244683   1.000000
    -0.431576   -0.481538   -1.000000
    -0.099535   0.728679    -1.000000
    -0.188428   0.156443    1.000000
    0.267051    0.318101    1.000000
    0.222114    -0.528887   -1.000000
    0.030369    0.113317    1.000000
    0.392321    0.026089    1.000000
    0.298871    -0.915427   -1.000000
    -0.034581   -0.133887   1.000000
    0.405956    0.206980    1.000000
    0.144902    -0.605762   -1.000000
    0.274362    -0.401338   1.000000
    0.397998    -0.780144   -1.000000
    0.037863    0.155137    1.000000
    -0.010363   -0.004170   1.000000
    0.506519    0.486619    -1.000000
    0.000082    -0.020625   1.000000
    0.057761    -0.155140   1.000000
    0.027748    -0.553763   -1.000000
    -0.413363   -0.746830   -1.000000
    0.081500    -0.014264   1.000000
    0.047137    -0.491271   1.000000
    -0.267459   0.024770    1.000000
    -0.148288   -0.532471   -1.000000
    -0.225559   -0.201622   1.000000
    0.772360    -0.518986   -1.000000
    -0.440670   0.688739    -1.000000
    0.329064    -0.095349   1.000000
    0.970170    -0.010671   -1.000000
    -0.689447   -0.318722   -1.000000
    -0.465493   -0.227468   -1.000000
    -0.049370   0.405711    1.000000
    -0.166117   0.274807    1.000000
    0.054483    0.012643    1.000000
    0.021389    0.076125    1.000000
    -0.104404   -0.914042   -1.000000
    0.294487    0.440886    -1.000000
    0.107915    -0.493703   -1.000000
    0.076311    0.438860    1.000000
    0.370593    -0.728737   -1.000000
    0.409890    0.306851    -1.000000
    0.285445    0.474399    -1.000000
    -0.870134   -0.161685   -1.000000
    -0.654144   -0.675129   -1.000000
    0.285278    -0.767310   -1.000000
    0.049548    -0.000907   1.000000
    0.030014    -0.093265   1.000000
    -0.128859   0.278865    1.000000
    0.307463    0.085667    1.000000
    0.023440    0.298638    1.000000
    0.053920    0.235344    1.000000
    0.059675    0.533339    -1.000000
    0.817125    0.016536    -1.000000
    -0.108771   0.477254    1.000000
    -0.118106   0.017284    1.000000
    0.288339    0.195457    1.000000
    0.567309    -0.200203   -1.000000
    -0.202446   0.409387    1.000000
    -0.330769   -0.240797   1.000000
    -0.422377   0.480683    -1.000000
    -0.295269   0.326017    1.000000
    0.261132    0.046478    1.000000
    -0.492244   -0.319998   -1.000000
    -0.384419   0.099170    1.000000
    0.101882    -0.781145   -1.000000
    0.234592    -0.383446   1.000000
    -0.020478   -0.901833   -1.000000
    0.328449    0.186633    1.000000
    -0.150059   -0.409158   1.000000
    -0.155876   -0.843413   -1.000000
    -0.098134   -0.136786   1.000000
    0.110575    -0.197205   1.000000
    0.219021    0.054347    1.000000
    0.030152    0.251682    1.000000
    0.033447    -0.122824   1.000000
    -0.686225   -0.020779   -1.000000
    -0.911211   -0.262011   -1.000000
    0.572557    0.377526    -1.000000
    -0.073647   -0.519163   -1.000000
    -0.281830   -0.797236   -1.000000
    -0.555263   0.126232    -1.000000
    

    为方便学习,免去下载步骤(下载需要积分),故直接将数据粘贴在上面,如若有异常,请下载csv格式的原始数据。
    训练集和测试集数据下载地址:
    http://download.csdn.net/download/csqazwsxedc/10271147

    参考:
    《统计学习方法》
    《Machine Learning in Action》

    展开全文
  • 使用SVM支持向量机进行鸢尾花分类_Python实现-附件资源
  • 支持向量机SVM理解与python调用

    千次阅读 2022-03-24 12:47:00
    (1)什么是支持向量机 有一个故事讲得挺好,我觉得用来初步理解SVM的原理和作用非常合适。具体是这样说的,桌子上放着两种颜色的球,球数量少的时候可以用一根木棍分开,这个木棍其实就是SVM,起着分割两类的作用。...
  • 1.有数据集 2.麻雀算法优化支持向量机python代码
  • 在机器学习领域,支持向量机SVM(Support Vector Machine)是一个有监督的学习模型,通常用来进行模式识别、分类(异常值检测)以及回归分析。 其具有以下特征:  (1)SVM可以表示为凸优化问题,因此可以利用已知的有效...
  • 结合《统计学习方法》以及一些资料,写出自己对SVM算法的理解,并且用Python+Numpy实现了SMO算法
  • StockProdiction-master,股票预测SVMpython代码,在pycharm上可以使用

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 24,494
精华内容 9,797
关键字:

svm支持向量机python代码