diff --git a/docs/6.支持向量机.md b/docs/6.支持向量机.md index de2cb9ad..1b16f52b 100644 --- a/docs/6.支持向量机.md +++ b/docs/6.支持向量机.md @@ -11,8 +11,8 @@ ## 支持向量机 场景 -* 如果把所有的点看作地雷,那么我们(超平面)得找到最近所有的地雷,并保证我们离它最远。 -* 所以:选择D会比B、C分隔的效果要好很多。 +* 要给左右两边的点进行分类 +* 明显发现:选择D会比B、C分隔的效果要好很多。 ![线性可分](/images/6.SVM/SVM_3_linearly-separable.jpg) @@ -23,7 +23,7 @@ ![k_2](/images/6.SVM/k_2.jpg "k_2") -对于上述的苹果和香蕉,我们想象为2中水果类型的炸弹。(保证距离最近的炸弹,距离它们最远) +对于上述的苹果和香蕉,我们想象为2种水果类型的炸弹。(保证距离最近的炸弹,距离它们最远) 1. 寻找最大分类间距 2. 转而通过拉格朗日函数求优化的问题 @@ -74,10 +74,9 @@ This is the simplest kind of SVM (Called an LSVM) Support Vectors are those data * 类别标签用-1、1,是为了后期方便 \\(lable*(w^Tx+b)\\) 的标识和距离计算;如果 \\(lable*(w^Tx+b)>0\\) 表示预测正确,否则预测错误。 * 现在目标很明确,就是要找到`w`和`b`,因此我们必须要找到最小间隔的数据点,也就是前面所说的`支持向量`。 * 也就说,让最小的距离取最大.(最小的距离:就是最小间隔的数据点;最大:就是最大间距,为了找出最优超平面--最终就是支持向量) - * 怎么理解呢? 例如: 如果把所有的点看作地雷,那么我们(超平面)得找到最近所有的地雷,并保证我们离它最远。 - * 目标函数:\\(arg: max\left( min(lable*(w^Tx+b))*\frac{1}{||w||} \right) \\) + * 目标函数:\\(arg: max_{关于w, b} \left( min[lable*(w^Tx+b)]*\frac{1}{||w||} \right) \\) 1. 如果 \\(lable*(w^Tx+b)>0\\) 表示预测正确,也称`函数间隔`,\\(||w||\\) 可以理解为归一化,也称`几何间隔`。 - 2. 令 \\(lable*(w^Tx+b)>=1\\), 因为-1~1之间,得到的点是存在误判的可能性,所以要保障min=1,才能更好降低噪音数据影响。 + 2. 令 \\(lable*(w^Tx+b)>=1\\), 因为0~1之间,得到的点是存在误判的可能性,所以要保障 \\(min[lable*(w^Tx+b)]=1\\),才能更好降低噪音数据影响。 3. 所以本质上是求 \\(arg: max_{关于w, b} \frac{1}{||w||} \\);也就说,我们约束(前提)条件是: \\(lable*(w^Tx+b)=1\\) * 新的目标函数求解: \\(arg: max_{关于w, b} \frac{1}{||w||} \\) * => 就是求: \\(arg: min_{关于w, b} ||w|| \\) (求矩阵会比较麻烦,如果x只是 \\(\frac{1}{2}*x^2\\) 的偏导数,那么。。同样是求最小值) @@ -88,14 +87,14 @@ This is the simplest kind of SVM (Called an LSVM) Support Vectors are those data * 设g(x,y)=M-φ(x,y) # 临时φ(x,y)表示下文中 \\(label*(w^Tx+b)\\) * 定义一个新函数: F(x,y,λ)=f(x,y)+λg(x,y) * a为λ(a>=0),代表要引入的拉格朗日乘子(Lagrange multiplier) - * 那么: \\(L(w,b,\alpha)=\frac{1}{2} * ||w||^2 + \sum_{i=1}^{n} \alpha * [1 - label * (w^Tx+b)]\\) - * 因为:\\(label*(w^Tx+b)>=1, \alpha>=0\\) , 所以 \\(\alpha*[1-label*(w^Tx+b)]<=0\\) , \\(\sum_{i=1}^{n} \alpha * [1-label*(w^Tx+b)]<=0\\) + * 那么: \\(L(w,b,\alpha)=\frac{1}{2} * ||w||^2 + \sum_{i=1}^{n} \alpha_i * [1 - label * (w^Tx+b)]\\) + * 因为:\\(label*(w^Tx+b)>=1, \alpha>=0\\) , 所以 \\(\alpha*[1-label*(w^Tx+b)]<=0\\) , \\(\sum_{i=1}^{n} \alpha_i * [1-label*(w^Tx+b)]<=0\\) * 相当于求解: \\(max_{关于\alpha} L(w,b,\alpha) = \frac{1}{2} *||w||^2\\) * 如果求: \\(min_{关于w, b} \frac{1}{2} *||w||^2\\) , 也就是要求: \\(min_{关于w, b} \left( max_{关于\alpha} L(w,b,\alpha)\right)\\) * 现在转化到对偶问题的求解 * \\(min_{关于w, b} \left(max_{关于\alpha} L(w,b,\alpha) \right) \\) >= \\(max_{关于\alpha} \left(min_{关于w, b}\ L(w,b,\alpha) \right) \\) * 现在分2步 - * 先求: \\(min_{关于w, b} L(w,b,\alpha)=\frac{1}{2} * ||w||^2 + \sum_{i=1}^{n} \alpha * [1 - label * (w^Tx+b)]\\) + * 先求: \\(min_{关于w, b} L(w,b,\alpha)=\frac{1}{2} * ||w||^2 + \sum_{i=1}^{n} \alpha_i * [1 - label * (w^Tx+b)]\\) * 就是求`L(w,b,a)`关于[w, b]的偏导数, 得到`w和b的值`,并化简为:`L和a的方程`。 * 参考: 如果公式推导还是不懂,也可以参考《统计学习方法》李航-P103<学习的对偶算法> ![计算拉格朗日函数的对偶函数](/images/6.SVM/SVM_5_Lagrangemultiplier.png) @@ -111,9 +110,7 @@ This is the simplest kind of SVM (Called an LSVM) Support Vectors are those data * 这一结论十分直接,SVM中的主要工作就是要求解 alpha. -### SMO高效优化算法 - -SMO 是 SVM最流行的一种实现 +### SMO 高效优化算法 * SVM有很多种实现,最流行的一种实现是: `序列最小优化(Sequential Minimal Optimization, SMO)算法`。 * 下面还会介绍一种称为`核函数(kernel)`的方式将SVM扩展到更多数据集上。 @@ -215,7 +212,7 @@ def smoSimple(dataMatIn, classLabels, C, toler, maxIter): """smoSimple Args: - dataMatIn 数据集 + dataMatIn 特征集合 classLabels 类别标签 C 松弛变量(常量值),允许有些数据点可以处于分隔面的错误一侧。 控制最大化间隔和保证大部分的函数间隔小于1.0这两个目标的权重。 @@ -247,7 +244,7 @@ def smoSimple(dataMatIn, classLabels, C, toler, maxIter): # print 'alphas=', alphas # print 'labelMat=', labelMat # print 'multiply(alphas, labelMat)=', multiply(alphas, labelMat) - # 我们预测的类别 y = w^Tx[i]+b; 其中因为 w = Σ(1~n) a[n]*lable[n]*x[n] + # 我们预测的类别 y[i] = w^Tx[i]+b; 其中因为 w = Σ(1~n) a[n]*lable[n]*x[n] fXi = float(multiply(alphas, labelMat).T*(dataMatrix*dataMatrix[i, :].T)) + b # 预测结果与真实结果比对,计算误差Ei Ei = fXi - float(labelMat[i]) @@ -325,7 +322,7 @@ def smoSimple(dataMatIn, classLabels, C, toler, maxIter): return b, alphas ``` -[完整代码地址:SVM简化版:应用简化版SMO算法处理小规模数据集](https://github.com/apachecn/MachineLearning/blob/master/src/python/6.SVM/svm-simple.py): +[完整代码地址:SVM简化版,应用简化版SMO算法处理小规模数据集](https://github.com/apachecn/MachineLearning/blob/master/src/python/6.SVM/svm-simple.py): [完整代码地址:SVM完整版,使用完整 Platt SMO算法加速优化,优化点:选择alpha的方式不同](https://github.com/apachecn/MachineLearning/blob/master/src/python/6.SVM/svm-complete_Non-Kernel.py): @@ -340,19 +337,19 @@ def smoSimple(dataMatIn, classLabels, C, toler, maxIter): * 如果觉得特征空间很装逼、很难理解。 * 可以把核函数想象成一个包装器(wrapper)或者是接口(interface),它能将数据从某个很难处理的形式转换成为另一个较容易处理的形式。 * 经过空间转换后:低维需要解决的非线性问题,就变成了高维需要解决的线性问题。 -* SVM 优化特别好的地方,在于所有的运算都可以写成内积(inner product: 是指2个向量相乘,得到单个标量 或者 数值);内核替换成核函数的方式被称为`核技巧(kernel trick)`或者`核"变电"(kernel substation)` +* SVM 优化特别好的地方,在于所有的运算都可以写成内积(inner product: 是指2个向量相乘,得到单个标量 或者 数值);内积替换成核函数的方式被称为`核技巧(kernel trick)`或者`核"变电"(kernel substation)` * 核函数并不仅仅应用于支持向量机,很多其他的机器学习算法也都用到核函数。最流行的核函数:径向基函数(radial basis function) * 径向基函数的高斯版本,其具体的公式为: ![径向基函数的高斯版本](/images/6.SVM/SVM_6_radial-basis-function.jpg) -### 项目案例: 手写数字识别的优化(无核函数) +### 项目案例: 手写数字识别的优化(有核函数) #### 项目概述 ```python -你的老板要求:你写的那个手写书别程序非常好,但是它占用内存太大。顾客无法通过无线的方式下载我们的应用。 -所以:我们可以考虑使用支持向量机,保留支持向量就行(knn需要保留所有的向量),就可以获得可比的效果。 +你的老板要求:你写的那个手写识别程序非常好,但是它占用内存太大。顾客无法通过无线的方式下载我们的应用。 +所以:我们可以考虑使用支持向量机,保留支持向量就行(knn需要保留所有的向量),就可以获得非常好的效果。 ``` #### 开发流程 @@ -430,7 +427,7 @@ def loadImages(dirName): > 分析数据:对图像向量进行目测 -> 训练算法:采用两种不同的核函数,并对径向基和函数采用不同的设置来运行SMO算法 +> 训练算法:采用两种不同的核函数,并对径向基核函数采用不同的设置来运行SMO算法 ```python def kernelTrans(X, A, kTup): # calc the kernel or transform data to a higher dimensional space @@ -447,7 +444,7 @@ def kernelTrans(X, A, kTup): # calc the kernel or transform data to a higher di m, n = shape(X) K = mat(zeros((m, 1))) if kTup[0] == 'lin': - # linear kernel: m*n * n*1 = m*1, 求y值 + # linear kernel: m*n * n*1 = m*1 K = X * A.T elif kTup[0] == 'rbf': for j in range(m): @@ -550,12 +547,12 @@ def testDigits(kTup=('rbf', 10)): print("the test error rate is: %f" % (float(errorCount) / m)) ``` -> 使用算法:一个图像识别的完整应用还需要一些图像处理的只是,这里并不打算深入介绍 +> 使用算法:一个图像识别的完整应用还需要一些图像处理的知识,这里并不打算深入介绍 [完整代码地址](https://github.com/apachecn/MachineLearning/blob/master/src/python/6.SVM/svm-complete.py): * * * -* **作者:[片刻](http://www.apache.wiki/display/~jiangzhonglian) [geekidentity](http://www.apache.wiki/display/~houfachao)** +* **作者:[片刻](http://cwiki.apachecn.org/display/~jiangzhonglian) [geekidentity](http://cwiki.apachecn.org/display/~houfachao)** * [GitHub地址](https://github.com/apachecn/MachineLearning): * **版权声明:欢迎转载学习 => 请标注信息来源于 [ApacheCN](http://www.apachecn.org/)** diff --git a/src/python/6.SVM/svm-complete.py b/src/python/6.SVM/svm-complete.py index b5d8bf0e..27923244 100644 --- a/src/python/6.SVM/svm-complete.py +++ b/src/python/6.SVM/svm-complete.py @@ -61,7 +61,7 @@ def kernelTrans(X, A, kTup): # calc the kernel or transform data to a higher di m, n = shape(X) K = mat(zeros((m, 1))) if kTup[0] == 'lin': - # linear kernel: m*n * n*1 = m*1, 求y值 + # linear kernel: m*n * n*1 = m*1 K = X * A.T elif kTup[0] == 'rbf': for j in range(m):