自由体网站建设vr全景,中山app开发,网站的域名是什么意思,瀑布流网站源码下载目录
一、基于最大间隔分隔数据
二、寻找最大间隔
1. 最大间隔
2. 拉格朗日乘子法
3. 对偶问题
三、SMO高效优化算法
四、软间隔
五、SMO算法实现
1. 简化版SMO算法
2. 完整版SMO算法
3. 可视化决策结果
六、核函数
1. 线性不可分——高维可分
2. 核函数 …目录
一、基于最大间隔分隔数据
二、寻找最大间隔
1. 最大间隔
2. 拉格朗日乘子法
3. 对偶问题
三、SMO高效优化算法
四、软间隔
五、SMO算法实现
1. 简化版SMO算法
2. 完整版SMO算法
3. 可视化决策结果
六、核函数
1. 线性不可分——高维可分
2. 核函数
七、垃圾邮件分类
八、总结 上次实验使用的logistic回归是一种线性分类模型其基本思想是根据数据集训练出一个线性回归模型再使用sigmoid函数将输出映射到0到1范围内这个输出值就是样本预测为正例的概率根据概率分类样本因此logistic回归是根据所有数据样本来确定一个线性模型的。
这次实验实验的支持向量机Support Vector MachinesSVM和logistic回归很类似SVM也是一种解决二分类问题的线性分类算法与logistic回归不同的是SVM分类只考虑样本分界线附近的样本点即支持向量其选择划分数据集的超平面是只根据支持向量来决定的而logistic回归训练模型时所有样本都有参与计算因此logistic回归是考虑所有样本点的。因此它们的训练目标是不一样的logistic回归是为了得到最拟合数据集的线性模型而SVM是为了得到使支持向量之间间隔最大的超平面。
一、基于最大间隔分隔数据
我们先从一个简单的二维的数据集开始这个二维数据集中的样本都分布在二维平面其中“”和“-”分别代表两种类别的样本。要划分下面这个数据集我们需要一条能将正负样本区分隔开的直线。如下图所示。 寻找一条划分数据集的直线很简单但是会有一个问题划分数据集的直线可以有很多条我们究竟应该选择那一条直线呢 我们直观看上去肯定是选择红色的这条直线a0而不是其他的直线因为红色这条直线离正负样本的距离都较远使用它作为划分直线能够很好的将正负样本分隔开。而对于其他的直线它们离某一类的样本太接近了这样的划分直线虽然在训练集上划分效果很好但是遇到没见过的样本它的预测性能就可能比较差了比如很接近正样本的划分直线a1它在训练集上能完全将正负样本区分开但是如果遇到一个相对比较靠近负样本的样本它实际上是正样本但a1却会将其划分为负样本对于划分直线a2也是一样。
我们希望得到的划分直线的容忍性好鲁棒性好泛化能力强就需要选择一条使样本之间间隔最大的直线。
在二维数据集中划分数据集的是一条直线在三维数据集中划分数据集的就得是平面了那么再更高维的数据集中应该使用什么对象来划分数据集呢在高维数据集中用来划分数据集的对象被称为超平面也就是分类的决策边界。所有用来划分数据集的对象都可以称作超平面包括二维的直线和三维的平面。 SVM的训练目标就是找到一个能最大化分类边界的超平面用该超平面来分类预测样本。
二、寻找最大间隔
1. 最大间隔
既然支持向量机的目标是找到一个与正负样本间隔最大的超平面那么首先我们需要知道间隔的表达式。
对于训练数据 该数据集线性可分当且仅当
且 上式的w和x都是用向量来表示的w{w1,w2,...,wn)x{x1,x2,...,xn}。
这里我们使用的类别标签是-1和1而不是0和1因为使用1和-1我们可以通过一个统一的公式来表示间隔。
上式可以等价于 上式中c是一个任意的正常数我们可以将左右两边除以c得到 而w和b是我们要求的参数将其除以一个常数仍然还是参数w和b因此可以上式写作 根据的取值可以得到两个式子 可以用两个超平面方程来表示 如下图所示。 这样在超平面之上的样本分类为正样本在超平面之下的样本分类为负样本而我们要求的超平面的方程就是两个超平面中间的超平面。最大化正负样本之间的间隔就变为了最大化超平面和之间的距离。
两个超平面之间的距离为 从上图我们也能看出SVM求解线性模型的时候是只考虑支持向量的它要求的最大间隔也是支持向量之间的最大间隔具体量化这个距离是根据支持向量到分隔超平面的距离计算的需要计算的就是正负支持向量到分隔超平面的距离之和。
比如正例支持向量到分隔超平面的距离就是w是超平面的法向量 负例支持向量到到分隔超平面的距离与正例相同而那么分类间隔就是 和上面计算的结果是一样的感觉上面计算的更好理解一点。
现在我们要求解的问题就变为寻找参数w和b使得分类间隔最大 我们可以将上式改为 为什么改成而不是呢因为在后面使用拉格朗日乘子法求解时比较方便对w求导能得到w的表达式便于计算。
下面使用一个简单的例子来计算求解最佳参数wb。 上面是一个简单的二维数据集只包含三个样本其中蓝色的是正样本红色的是负样本。
我们要求解的是 将上述三个样本点(23)、(34)、(21)代入方程得到 将上式消去b得到 在系数坐标轴中画出两条直线和。 上图中横坐标为x1纵坐标为x2。
同时满足上述两式的点在图中浅蓝色区域内我们需要的是在这个区域内寻找使得最小的参数w和b的最小值也就是的最小值的最小值在坐标系中可以表示为点到原点的距离我们可以做一个与这个区域范围下方相切的圆心为原点的圆那么到原点距离最短的点就是切点这个点的坐标是(0,1)也就是。
把代入原本的三式可以得到 根据上述三式可以得到b-2
最终得到的超平面方程为 使用该超平面划分数据集如下图。 上述是直接根据样本代入约束条件得到满足条件的参数范围并从中寻找使得最小的参数w、b这样的方法实现比较简单但它有个问题就是在高维的时候计算需要的样本也会很多n维的数据集需要n1个样本得到n1个方程计算起来就比较麻烦了而且这种方法计算的极小值点可能是不唯一的。因此我们需要使用其他的方法来求解问题。
2. 拉格朗日乘子法
拉格朗日乘子法是一种多元函数在变量受到条件约束时求极值的方法SVM求解的目标正好就属于这里问题因此可以使用拉格朗日乘子法来求解问题。
给定一个目标函数希望找到 在满足约束条件g(x)0的前提 下使得f(x)有最小值。该约束优化问题记为 可建立拉格朗日函数 其中 λ 称为拉格朗日乘数。因此可将原本的约束优化问题转换成等价的 无约束优化问题 。
分别对待求解参数求偏导可得 一般联立方程组可以得到相应的解。
将约束等式 g(x)0 推广为不等式 g(x)≤0。这个约束优化问题可改 同理其拉格朗日函数为 其约束范围为不等式因此可等价转换成Karush-Kuhn-TuckerKKT条件 在此基础上通过优化方式如二次规划或SMO求解其最优解。
3. 对偶问题
现在回到待求解问题上我们的待求解问题是 约束条件是需要更改成下式 接着引入拉格朗日乘子得到拉格朗日函数 令对w和b的偏导为0 得到 原式可以写作 将代入可以得到 化简得到 这样原问题就转换为对偶问题了得到的关系式是关于变量的那么对这个式子我们需要求的是还是。这个可以证明最后要求的目标是也就是 根据KKT条件可以得到如下的约束条件 前面说过在超平面和上的样本就是划分边界上的样本点也就是支持向量对应也就是说支持向量都满足关系式此时。而对应其他不在划分边界上的点又因为所以根据上面推导出的对于这类不在划分边界上的样本点都有样本单项计算的结果为0该样本对w的值没有贡献也就是前面说的最终模型只与支持向量有关其他样本都会被舍弃。如下图所示。 三、SMO高效优化算法
前面我们已经将原问题转换为对偶问题 对于这个问题我们该如何求解呢对于这类二次规划问题的求解方法有很多其中一种就是SMO算法SMO表示序列最小优化Sequential Minimal Optimization。SMO算法是将大优化问题分解为多个小优化问题来求解的。这些小优化问题往往很容易求解并且对它们进行顺序求解的结果与将它们作为整体求解的结果是完全一致的同时总求解的时间还会短很多。
SMO算法的目标是求出一系列的和b求出了这些就能根据对应的关系式得到权重w也就能得到划分数据集的超平面了。
SMO算法的工作原理是 1. 选取两个需要更新的变量和 2. 固定和以外的参数求解对偶问题更新和 重复执行上述两个步骤直到模型收敛。
仅考虑和时对偶问题的约束条件变为 更新公式为 算法流程 假设最优解为
可得 根据w和b就能得到分隔超平面 四、软间隔
前面的实现都有一个假设数据100%线性可分也就是能找到一个划分边界使得数据集中的样本完全分类正确这样的模型不允许有数据点处于分隔面的错误一侧。但实际上一般的数据集都不会是100%线性可分的都会或多或少存在一些不能正确分类的数据点因此我们需要引入松弛变量和惩罚系数的概念。
原问题变为 其中C是惩罚因子用于控制“最大化间隔”和“保证大部分点的函数间隔小于1.0”这两个目标的权重。在优化算法的实现代码中C是一个参数可以通过调整C来得到不同的结果。
是松弛变量作用是给限制条件加上一个值使得等式重新成立。
接着在使用拉格朗日乘子法构造目标函数 将上式分别对w、b、求偏导将得到的结果代入原式就能得到对偶问题 五、SMO算法实现
1. 简化版SMO算法
SMO算法的完整实现比较复杂在此之前我们先实现一个简化版的SMO算法之后再实现完整版。
完整版SMO算法再外循环确定要优化的最佳alpha对而简化版会跳过这个步骤改为从遍历alpha集合中的每一个alpha值然后在剩下的alpha集合中随机选取另一个alpha从而构成alpha对。
在实现简化版SMO算法之前需要先定义三个辅助函数分别用于读取数据集、随机选择alpha值、限制alpha值的范围。
# 读取数据集
def loadDataSet(filename):dataSet []labelList []fp open(filename)lines fp.readlines()for line in lines:lineSplit line.strip().split()dataSet.append([float(lineSplit[0]), float(lineSplit[1])])labelList.append(float(lineSplit[2]))return dataSet, labelList # 随机选择alpha
def selectJrand(i, m):j i# 随机选择一个下标不等于j的alpha的下标while j i:j int(random.uniform(0, m))return j# 限制alpha值的范围
def clipAlpha(aj, H, L):if aj H:aj Hif L aj:aj Lreturn aj部分数据集 读取数据集 SMO算法伪代码如下 1. 创建一个alpha向量并初始化为全零 2. 当迭代次数小于最大迭代次数时 2.1. 对数据集中的每个数据向量 2.1.1.判断该数据向量是否需要优化 2.1.1.1. 随机选择另一个数据向量 2.1.1.2. 同时优化这两个向量 2.1.1.3. 如果两个向量都不能被优化则退出内循环 2.2. 如果所有向量都没有被优化增加迭代数目继续下一次循环 代码实现如下
# C惩罚因子toler容错率maxIter最大迭代次数
def smoSimple(dataSet, classLabels, C, toler, maxIter):dataSet np.mat(dataSet)classLabels np.mat(classLabels).transpose()b 0m, n dataSet.shapealphas np.mat(np.zeros((m, 1)))# 迭代次数iter 0while iter maxIter:alphaPairsChanged 0for i in range(m):fXi float(np.multiply(alphas, classLabels).T * (dataSet * dataSet[i, :].T)) bEi fXi - classLabels[i]# 判断是否要对该alpha值优化误差超过容错率且alpha不等于0或Cif classLabels[i] * Ei -toler and alphas[i] C \or classLabels[i] * Ei toler and alphas[i] 0:j selectJrand(i, m)fXj float(np.multiply(alphas, classLabels).T * (dataSet * dataSet[j, :].T)) bEj fXj - classLabels[j]# 需要使用copy复制一个数组不然就是直接将对象赋值过去了不会重新开辟空间alphaIold alphas[i].copy()alphaJold alphas[j].copy()# 计算alpha值的范围大于C和小于0的值都将调整为C和0if classLabels[i] ! classLabels[j]:L max(0, alphas[j] - alphas[i])H min(C, C alphas[j] - alphas[i])else:L max(0, alphas[j] alphas[i] - C)H min(C, alphas[j] alphas[i])if L H:print(L H)continueeta 2. * dataSet[i, :] * dataSet[j, :].T - dataSet[i, :] * dataSet[i, :].T \- dataSet[j, :] * dataSet[j, :].Tif eta 0:print(eta 0)continuealphas[j] - classLabels[j] * (Ei - Ej) / eta# 限制alpha的值在L到H之间alphas[j] clipAlpha(alphas[j], H, L)if abs(alphas[j] - alphaJold) 0.00001:print(j not moving enough)continuealphas[i] classLabels[j] * classLabels[i] * (alphaJold - alphas[j])b1 b - Ei - classLabels[i] * (alphas[i] - alphaIold) * dataSet[i, :] * dataSet[i, :].T \- classLabels[j] * (alphas[j] - alphaJold) * dataSet[i, :] * dataSet[j, :].Tb2 b - Ej - classLabels[i] * (alphas[i] - alphaIold) * dataSet[i, :] * dataSet[j, :].T \- classLabels[j] * (alphas[j] - alphaJold) * dataSet[j, :] * dataSet[j, :].Tif alphas[i] 0 and alphas[i] C:b b1elif alphas[j] 0 and alphas[j] C:b b2else:b (b1 b2) / 2alphaPairsChanged 1print(iter:, iter, i:, i, pairs changed, alphaPairsChanged)if alphaPairsChanged 0:iter 1else:iter 0print(iteration number:, iter)return b, alphas
上述代码首先将数据集dataSet和标签转换为矩阵便于后续计算。随后进行迭代更新alpha每次迭代遍历alpha值对于每一个alpha值先使用当前的模型计算样本xi的预测结果fXi这个值是概率值并不是真实的分类将预测值与真实值相减得到预测误差Ei。随后进行判断是否要对该当前alpha值进行优化预测误差超过容错率且alpha值不等于0或C就需要优化。
alpha优化过程为随机选取另一个alpha 计算xj样本的预测结果fXj和误差Ej然后计算alpha值的最大范围限制alpha值在0-C之内。根据计算公式计算值。然后就可以更新和的值了首先根据公式计算的新值并限制其范围在0-C之内如果更新的值与原值相差小于一个很小的阈值0.00001那么说明的更新跨度不够大跳过当前循环。如果大于该阈值就接根据公式着更新最后再更新b。
测试
调用简化版SMO函数计算结果输出b、大于0的alpha值以及支持向量
dataSet, classLabels loadDataSet(os.getcwd() /svm_data/data/testSet.txt)
b, alphas smoSimple(dataSet, classLabels, 0.6, 0.001, 40)
print(b)
print(alphas[alphas 0])
i 0
for alpha in alphas:if alpha 0.:print(dataSet[i], classLabels[i])i 1 运行结果 2. 完整版SMO算法
完整版SMO算法有多个函数都需要使用一些参数可以将这些参数和函数封装成一个类包含算法所要用到的各个数据以及完整版SMO算法所需要的各类函数。
完整版SMO算法在内循环也就是alpha值的更改和代数运算的步骤与简化版SMO算法是一样的它们之间的不同在于选择alpha的方式也就是外循环。
完整版SMO算法在外循环中选择第一个alpha值其选择alpha值的方式有两种一种是在数据集上进行单遍扫描另一种方式是在非边界alpha中实现单遍扫描非边界alpha指的是那些不等于边界0或C的alpha值。完整版SMO算法在选择alpha值时会交替使用上述两种方法。
SMO算法需要的参数有数据集dataSet类别标签classLabels惩罚因子C容错率toler。
定义一个Svm类包含上述数据对象
class Svm:def __init__(self, dataSet, classLabels, C, toler):self.X dataSetself.labels classLabelsself.C Cself.toler tolerself.m dataSet.shape[0]self.n dataSet.shape[1]self.alphas np.mat(np.zeros((self.m, 1)))self.b 0self.eCache np.mat(np.zeros((self.m, 2)))self.w np.zeros((self.n, 1))
接着需要定义三个辅助函数分别用于计算误差E、选择alpha值、计算误差E并将误差值存入变量eCache中这些类都要封装在类Svm中作为Svm类的成员函数。 def calcEk(self, k):fXk np.multiply(self.alphas, self.labels).T * \(self.X * self.X[k, :].T) self.bEk fXk - self.labels[k]return Ekdef selectJ(self, i, Ei):maxK -1maxDeltaE 0Ej 0self.eCache[i] [1, int(Ei)]validEcacheList np.nonzero(self.eCache[:, 0].A)[0]if len(validEcacheList) 1:for k in validEcacheList:if k i:continueEk self.calcEk(k)deltaE abs(Ei - Ek)if deltaE maxDeltaE:maxK kmaxDeltaE deltaEEj Ekreturn maxK, Ejelse:j selectJrand(i, self.m)Ej self.calcEk(j)return j, Ejdef updataEk(self, k):Ek self.calcEk(k)self.eCache[k] [1, int(Ek)] 定义优化alpha值的函数其计算步骤与前面实现的简化版SMO函数是一样的只是不用传入各类参数而是使用类中的数据成员。 def innerL(self, i):Ei self.calcEk(i)# print(Ei)# print(self.labels[i] * Ei)if (self.labels[i] * Ei -self.toler) and (self.alphas[i] self.C) \or (self.labels[i] * Ei self.toler) and (self.alphas[i] 0):j, Ej self.selectJ(i, Ei)alphaIold self.alphas[i].copy()alphaJold self.alphas[j].copy()if self.labels[i] ! self.labels[j]:L max(0, self.alphas[j] - self.alphas[i])H min(self.C, self.C self.alphas[j] - self.alphas[i])else:L max(0, self.alphas[j] self.alphas[i] - self.C)H min(self.C, self.alphas[j] self.alphas[i])if L H:print(L H)return 0eta 2. * self.X[i, :] * self.X[j, :].T - self.X[i, :] * self.X[i, :].T \- self.X[j, :] * self.X[j, :].Tif eta 0:print(eta 0)return 0self.alphas[j] - self.labels[j] * (Ei - Ej) / etaself.alphas[j] clipAlpha(self.alphas[j], H, L)self.updataEk(j)if abs(self.alphas[j] - alphaJold) 0.00001:print(j not moving enough)return 0self.alphas[i] self.labels[j] * self.labels[i] * (alphaJold - self.alphas[j])self.updataEk(i)b1 self.b - Ei - self.labels[i] * (self.alphas[i] - alphaIold) \* self.X[i, :] * self.X[i, :].T - self.labels[j] \* (self.alphas[j] - alphaJold) * self.X[i, :] * self.X[j, :].Tb2 self.b - Ej - self.labels[i] * (self.alphas[i] - alphaIold) \* self.X[i, :] * self.X[j, :].T - self.labels[j] \* (self.alphas[j] - alphaJold) * self.X[j, :] * self.X[j, :].Tif self.alphas[i] 0 and self.alphas[i] self.C:self.b b1elif self.alphas[j] 0 and self.alphas[j] self.C:self.b b2else:self.b (b1 b2) / 2return 1else:return 0
完整版SMO算法同时也是外循环代码在外循环中选取alpha值接着调用内循环函数innerL优化alpha值。 def smoP(self, maxIter, kTup(lin, 0)):iter 0entireSet TruealphaPairsChanged 0while iter maxIter and (alphaPairsChanged 0 or entireSet):alphaPairsChanged 0if entireSet:for i in range(self.m):alphaPairsChanged self.innerL(i)print(fullset, iter:, iter, i:, i, pairs changed, alphaPairsChanged)iter 1else:nonBoundIs np.nonzero((self.alphas.A 0) * (self.alphas.A self.C))[0]for i in nonBoundIs:alphaPairsChanged self.innerL(i)print(non-bound, iter:, iter, i:, i, pairs changed, alphaPairsChanged)iter 1if entireSet:entireSet Falseelif alphaPairsChanged 0:entireSet Trueprint(iteration number:, iter)# 根据训练得到的alphas计算权重for i in range(self.m):self.w np.multiply(self.alphas[i] * self.labels[i], self.X[i, :].T)
该函数会交替使用使用两种选择alpha值的方式在entireSet为True的时候使用在整个数据集上选取alpha值的方法在entireSet为False的时候选择在非边界alpha选择alphaz值的方法在使用过整个数据集选取的方法后就会置entire为False如果有任意一对alpha值改变下一次循环就会选择非边界alpha选取方法如果没有alpha更改则下一次仍会选择在整个数据集上选取的方法。
smoP函数可以看作是训练函数调用该函数就能计算得到最佳参数w和b为了方便该函数没有直接返回w和b而是将其保存在类中。
得到训练后的模型参数后就可以输入样本进行预测了我们需要定义一个分类函数。 # 对一维数据分类def classfy1(self, tdata):tdata np.mat(tdata)y_hat tdata * np.mat(self.w) bif y_hat 0:return 1if y_hat 0:return -1# 对二维数据分类def classfy2(self, tdatas):tdatas np.mat(tdatas)y_hat tdatas np.mat(self.w) by_hat[y_hat 0] 1y_hat[y_hat 0] -1return np.array(y_hat)
这里我定义了两个分类函数一个是对一维数据进行分类单个样本另一个是对二维样本进行分类多个样本 。一维数据直接套公式就能得到结果然后将大于0的结果分类为1小于0的结果分类为-1。二维数据需要使用矩阵进行计算计算后使用y_hat[y_hat 0]和y_hat[y_hat 0]分别取大于0和小于0的预测结果将其分别赋值为1和-1。
单样本分类
svm Svm(np.mat(dataSet), np.mat(classLabels).transpose(), 0.6, 0.001)
svm.smoP(40)
zzx svm.classfy1(dataSet[0])
预测结果 多样本分类
svm Svm(np.mat(dataSet), np.mat(classLabels).transpose(), 0.6, 0.001)
svm.smoP(40)
svm.classfy2(dataSet) 数据集 3. 可视化决策结果
如果想更直观的观察分类的结果我们可以使用绘图工具将分类结果可视化。
def plot_data(ax, X, y):dataS np.concatenate((np.array(X), np.array(y).reshape(-1, 1)), axis1)绘制数据集的散点图ax.scatter(dataS[dataS[:, -1] 1, :][:, 0], dataS[dataS[:, -1] 1, :][:, 1], s30, markerx, labelPositive, cblack)ax.scatter(dataS[dataS[:, -1] -1, :][:, 0], dataS[dataS[:, -1] -1, :][:, 1], s30, markero, labelNegative, cy)ax.set_xlabel(x1)ax.set_ylabel(x2)ax.set_title(Example Dataset 1)ax.legend()def plot_boundary(ax, clf, X):绘制超平面x_min, x_max X[:, 0].min() * 1.2, X[:, 0].max() * 1.1y_min, y_max X[:, 1].min() * 1.1, X[:, 1].max() * 1.1xx, 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()])Z clf.classfy2(np.c_[xx.ravel(), yy.ravel()])print(Z, Z.shape)Z Z.reshape(xx.shape)ax.contour(xx, yy, Z)
测试
测试不同惩罚因子C的分类结果
X_np dataSet
y classLabels
for c in [0.6, 25, 50]:modela Svm(np.mat(X_np), np.mat(y).transpose(), c, 0.001)modela.smoP(40)fig, ax plt.subplots()plot_data(ax, X_np, y)plot_boundary(ax, modela, np.array(X_np))ax.set_title(SVM Decision Boundary with C {} (Example Dataset 1).format(c))plt.show() 运行结果 不知道为什么这个多次运行有多种结果正常应该是C越小越松弛能容许的错误分类数越多C越大能允许的错误分类越少。这个数据集没有不能被正确分类的样本所以看不出来不同C值带来的不同结果。
我换了另一个有不能被正确分类的样本的数据集来测试这个数据集是.mat格式的好像是二进制文件我不知道怎么打开不知道里面是什么数据。一开始运行的时候负样本一个都不显示。 后面看了一下这个数据集的类别标签是0和1但是上面定义的Svm模型处理的类别标签是-1和1所以需要将类别标签0改为-1。
raw_data loadmat(os.getcwd() \svm_data\data\ex6data1.mat)
data pd.DataFrame(raw_data[X], columns[X1, X2])
data[y] raw_data[y].flatten()
X_np data[[X1, X2]].values
y data[y].values.astype(float)
y[y 0] -1
print(y)
c 20
modela Svm(np.mat(X_np), np.mat(y).transpose(), c, 0.001)
modela.smoP(40)
fig, ax plt.subplots()
plot_data(ax, X_np, y)
plot_boundary(ax, modela, np.array(X_np))
ax.set_title(SVM Decision Boundary with C {} (Example Dataset 1).format(c))
plt.show()
运行后虽然负样本出来了但是分隔线却没了应该是在坐标轴下面了多运行几次有时候会出来但是也是个很差的分隔线不知道为什么在这个数据集上运行的结果这么差。
没办法我只能用库函数了用库函数就能正确分类了。 可以看出C越小就越允许更多的样本被错误分类第一张图中有一个更靠近负例的正样本分割线能容许这样的样本存在因此没有过于要求将这个样本也分类到正例这样分类的结果就比较好。而下面两张图C比较大会更倾向于将所有样本都正确分类得出的结果反而不好。一般数据集中都会存在一些很难正确分类的样本适当降低C的值效果会比较好。
六、核函数
1. 线性不可分——高维可分
前面计算求解的前提都是数据集线性可分如果数据集线性不可分也就不存在一个能正确划分两类样本的分隔超平面此时应该怎么做
我们可以将样本从原始特征空间映射到一个更高维的特征空间中使得样本在这个高维的特征空间中线性可分。
如下图左边的二维特征空间中找不到一条能准确划分数据集的直线此时就可以将样本映射到高维空间中如右图。在右图中就能找到一个能准确划分数据集的平面了。 具体映射方法如下
对于左图无法找到一条能准确划分数据集的直线但可以使用一个圆来划分。
圆的方程为 变换将其映射到三维空间得到 变换得到的就是三维空间中的一个平面使用该平面就能准确划分数据集了。 使用核函数后原问题 就变换为 ,只以内积的形式出现
线性模型变换为
2. 核函数
将原始空间中的向量作为输入向量并返回特征空间转换后的数据空间,可能是高维中向量的点积的函数称为核函数。
核函数定义如下 根据Mercer定理只要对称函数值所对应的核矩阵半正定, 则该函数可作为核函数。
常用的核函数有 可视化决策
def plot_data(X, y, ax):绘制数据集的散点图positive data[data[y] 1]negative data[data[y] 0]ax.scatter(positive[X1], positive[X2], s20, markerx, labelPositive, cblack)ax.scatter(negative[X1], negative[X2], s20, markero, labelNegative, cy)ax.set_xlabel(x1)ax.set_ylabel(x2)ax.legend()def plot_boundary(ax, clf, X):绘制决策边界x_min, x_max X[:, 0].min() * 1.2, X[:, 0].max() * 1.1y_min, y_max X[:, 1].min() * 1.1, X[:, 1].max() * 1.1xx, 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()])Z Z.reshape(xx.shape)ax.contour(xx, yy, Z)
测试
import matplotlib.pyplot as plt
import pandas as pd
from scipy.io import loadmat
from sklearn import svmraw_data loadmat(os.getcwd() \svm_data\data\ex6data2.mat)
X, y raw_data[X], raw_data[y].ravel() # 确保 y 是一维数组
data pd.DataFrame(raw_data[X], columns[X1, X2])
data[y] y
sigmax [0.1, 0.2, 0.5]
for sigma in sigmax:gamma np.power(sigma, -2)clf svm.SVC(C1, kernelrbf, gammagamma)model clf.fit(X, y)fig, ax plt.subplots()plot_data(X, y, ax)plot_boundary(ax, model, X)ax.set_title(SVM Decision Boundary with σ {}.format(sigma))plt.show()
运行结果 可以看出sigma的值越大绘制出的决策边界就会越平滑但是不能很好的将两组数据划分出来划分的精确度比较低较大大的sigma值得出的是一种大致的分隔边界会有比较多的样本被错误分类容易造成欠拟合的情况。当sigma的值比较小时模型能很好的将两类样本分隔开在训练集上的精确度很高但这样泛化能力就比较差了在测试集上的预测能力可能就比较差了也就是产生过拟合的情况。
七、垃圾邮件分类
垃圾邮件数据集包含训练集和测试集使用loadmat函数分别读取训练集和测试集并从中按对应标签取出特征向量和类别标签使用径向基核构建svm分类器。
将模型训练好后进行预测将预测结果与实际标签比较计算错误率。
train_data loadmat(os.getcwd() \svm_data\data\spamTrain.mat)
test_data loadmat(os.getcwd() \svm_data\data\spamTest.mat)
XTrain, yTrain train_data[X], train_data[y].ravel() # 确保 y 是一维数组
XTest, yTest test_data[Xtest], test_data[ytest].ravel()
sigma 0.4
gamma np.power(sigma, -2)
svc svm.SVC(C1, kernellinear, gammagamma)
svc.fit(XTrain, yTrain)
y_predict svc.predict(XTest)
errorRate sum(y_predict ! yTest) / len(yTest)
print(错误率为, errorRate)
运行结果 这个错误率有点高换了些其他的sigma值测试还是这个错误率。可能这个数据集是线性可分的不用核函数。
将svm分类器的内核改为线性核linear
svc svm.SVC(C1, kernellinear)
运行结果 这个错误率就很低了。
八、总结
支持向量机也是一种线性分类模型它通过寻找不同类别样本之间的最大间隔从而得到最佳的模型参数w和b模型训练目标是计算得到一个最佳一个超平面该超平面能够最大化支持向量之间的间隔模型训练的时候只会考虑支持支持向量。支持向量之间的间隔可以计算得到是使用拉格朗日乘子法将其转换到对偶问题通过求解对偶问题来得到原问题的解。对偶问题的求解一般采用SMO算法来实现SMO算法的基本思想就是每次选取两个α进行更新根据对应的公式优化更新α参数得到最佳的α值后再根据α计算w再计算b最后得到训练好的线性模型使用该模型就能进行预测了。在遇到线性不可分的数据集时可以使用核函数将样本映射到高维空间中在高维空间求解。 文章转载自: http://www.morning.cbynh.cn.gov.cn.cbynh.cn http://www.morning.bpmnh.cn.gov.cn.bpmnh.cn http://www.morning.cytr.cn.gov.cn.cytr.cn http://www.morning.hblkq.cn.gov.cn.hblkq.cn http://www.morning.btwlp.cn.gov.cn.btwlp.cn http://www.morning.ykwqz.cn.gov.cn.ykwqz.cn http://www.morning.llmhq.cn.gov.cn.llmhq.cn http://www.morning.nkpml.cn.gov.cn.nkpml.cn http://www.morning.sgqw.cn.gov.cn.sgqw.cn http://www.morning.jrrqs.cn.gov.cn.jrrqs.cn http://www.morning.gsjzs.cn.gov.cn.gsjzs.cn http://www.morning.lywcd.cn.gov.cn.lywcd.cn http://www.morning.xxsrm.cn.gov.cn.xxsrm.cn http://www.morning.pzrpz.cn.gov.cn.pzrpz.cn http://www.morning.fqyqm.cn.gov.cn.fqyqm.cn http://www.morning.rwfp.cn.gov.cn.rwfp.cn http://www.morning.pgjyc.cn.gov.cn.pgjyc.cn http://www.morning.kxmyj.cn.gov.cn.kxmyj.cn http://www.morning.rnwmp.cn.gov.cn.rnwmp.cn http://www.morning.rdymd.cn.gov.cn.rdymd.cn http://www.morning.wwjft.cn.gov.cn.wwjft.cn http://www.morning.sdecsd.cn.gov.cn.sdecsd.cn http://www.morning.dxrbp.cn.gov.cn.dxrbp.cn http://www.morning.fssjw.cn.gov.cn.fssjw.cn http://www.morning.kbgzj.cn.gov.cn.kbgzj.cn http://www.morning.jcpq.cn.gov.cn.jcpq.cn http://www.morning.xrhst.cn.gov.cn.xrhst.cn http://www.morning.newfeiya.com.cn.gov.cn.newfeiya.com.cn http://www.morning.gjxr.cn.gov.cn.gjxr.cn http://www.morning.flfxb.cn.gov.cn.flfxb.cn http://www.morning.ygkq.cn.gov.cn.ygkq.cn http://www.morning.synlt.cn.gov.cn.synlt.cn http://www.morning.rqfnl.cn.gov.cn.rqfnl.cn http://www.morning.wbyqy.cn.gov.cn.wbyqy.cn http://www.morning.ktbjk.cn.gov.cn.ktbjk.cn http://www.morning.ggcjf.cn.gov.cn.ggcjf.cn http://www.morning.dskzr.cn.gov.cn.dskzr.cn http://www.morning.qsmch.cn.gov.cn.qsmch.cn http://www.morning.jxfsm.cn.gov.cn.jxfsm.cn http://www.morning.mgbcf.cn.gov.cn.mgbcf.cn http://www.morning.wjlhp.cn.gov.cn.wjlhp.cn http://www.morning.xmbhc.cn.gov.cn.xmbhc.cn http://www.morning.pgjyc.cn.gov.cn.pgjyc.cn http://www.morning.wctqc.cn.gov.cn.wctqc.cn http://www.morning.pfgln.cn.gov.cn.pfgln.cn http://www.morning.jfjqs.cn.gov.cn.jfjqs.cn http://www.morning.qnjcx.cn.gov.cn.qnjcx.cn http://www.morning.kydrb.cn.gov.cn.kydrb.cn http://www.morning.sxmbk.cn.gov.cn.sxmbk.cn http://www.morning.mkpkz.cn.gov.cn.mkpkz.cn http://www.morning.bxch.cn.gov.cn.bxch.cn http://www.morning.fcwb.cn.gov.cn.fcwb.cn http://www.morning.rfhwc.cn.gov.cn.rfhwc.cn http://www.morning.jxtbr.cn.gov.cn.jxtbr.cn http://www.morning.rrgqq.cn.gov.cn.rrgqq.cn http://www.morning.rpms.cn.gov.cn.rpms.cn http://www.morning.cmhkt.cn.gov.cn.cmhkt.cn http://www.morning.dytqf.cn.gov.cn.dytqf.cn http://www.morning.bndkf.cn.gov.cn.bndkf.cn http://www.morning.rbmnq.cn.gov.cn.rbmnq.cn http://www.morning.rmyqj.cn.gov.cn.rmyqj.cn http://www.morning.pdbgm.cn.gov.cn.pdbgm.cn http://www.morning.fsnhz.cn.gov.cn.fsnhz.cn http://www.morning.ygxf.cn.gov.cn.ygxf.cn http://www.morning.fdsbs.cn.gov.cn.fdsbs.cn http://www.morning.jfxdy.cn.gov.cn.jfxdy.cn http://www.morning.wyctq.cn.gov.cn.wyctq.cn http://www.morning.npbnc.cn.gov.cn.npbnc.cn http://www.morning.ryjl.cn.gov.cn.ryjl.cn http://www.morning.kgrwh.cn.gov.cn.kgrwh.cn http://www.morning.fslxc.cn.gov.cn.fslxc.cn http://www.morning.ndmbd.cn.gov.cn.ndmbd.cn http://www.morning.mmclj.cn.gov.cn.mmclj.cn http://www.morning.jrsgs.cn.gov.cn.jrsgs.cn http://www.morning.ljllt.cn.gov.cn.ljllt.cn http://www.morning.jljwk.cn.gov.cn.jljwk.cn http://www.morning.baohum.com.gov.cn.baohum.com http://www.morning.lcbnb.cn.gov.cn.lcbnb.cn http://www.morning.jqsyp.cn.gov.cn.jqsyp.cn http://www.morning.mqfw.cn.gov.cn.mqfw.cn