本博文将介绍支持向量机的一些理论并使用WEKA来得到一个分类器。在介绍支持向量机之前,先介绍感知机的一些知识。
感知机是二类分类的线性分类模型,其输入为实例的特征向量,输出为实例类别。感知机对应于输入空间中的实例划分为正负两类的分离超平面,属于判别模型。感知机的描述如下:
给定一个训练数据集
T={(x1,y1),(x2,y2),...,(xN,yN)}
其中 xi 是输入空间, yi 是类别。求参数 w,b ,使得损失函数极小化问题的求解
minw,bL(w,b)=−∑xi∈M(wxi+b)
其中M是误分类点的集合。
具体采用随机梯度下降算法求解(不适用批量下降算法的原因是:批量下降算法会慢,虽然其选取的梯度都是最“抖”的那个,但是真正要效率更好的话,还是随机下降更高)。
感知机问题的最后求解,会得到一个分离超平面,会将两类分成两部分。这样的分离超平面是有无穷多个的。但是哪个分离超平面更好?如何找到一个更好的分离超平面?这就是支持向量机的问题了。
支持向量机的间隔最大化和核技巧,使它即可以处理线性分类问题,也可以处理非线性问题。
上面介绍完感知机问题后,其实线性可分支持向量机,就是求解感知机问题的一个最大间隔超平面。首先这个最大间隔超平面是存在的,且唯一的,存在唯一性可以通过数学证明(反证法可以证明得到唯一性)。
先给出线性可分支持向量机的原始问题的描述:
minw,b12||w||2
s.t yi(w⋅xi+b)−1≥0,i=1,2,...,N
为了求解线性可分支持向量机的原始问题,可以应用拉格朗日对偶性来得到原始问题的最优解。具体的过程这里不再叙述。可以参见李航《统计学习方法》。
实际情况中,训练数据集往往并不是线性可分的,因为存在着噪声以及特异点。当然,我们可以先去除掉噪声数据再进行线性可分的操作,但是如何判断噪声数据实际上是很麻烦的事。那么就推广到了更一般的情况—-线性支持向量机。
上面线性可分支持向量机的间隔是硬间隔最大化,现在这种情况下,应当是软间隔最大化。
为了解决这个问题需要引入松弛变量的概念(在线性规划问题中,单纯形算法也引入了松弛变量,其实道理是类似的)。
多的不叙述了,很多参考书上有具体的证明过程,给出问题。
minw,b12||w||2+C∑Ni=1ε
s.t yi(w⋅xi+b)−1+ε≥0,i=1,2,...,N
其中 ε 是松弛变量。
同样可以通过对偶的方式求解出解。
非线性分类其实是最常见的了,求解这类问题需要引入核技巧。对于数学系的笔者来说,核函数的理解还是很难啊(应该是没学过泛函分析的结果)。简单点说,通过核技巧,可以将非线性问题转换成线性问题。这样就可以通过线性可分支持向量问题来求解了。
(1)多项式核函数
K(x,z)=(x⋅z+1)p
(2)高斯核函数
K(x,z)=exp(−||x−z||22σ2)
当然可以自定义核函数,但是需要满足下面条件:
自定义的核函数应该是正定的。其充要条件:
设 K:χ×χ→R 是对称函数,则 K(x,z) 为正定核函数的充要条件是对任意 xi∈χ,i=1,2,...,m , K(x,z) 对应的Gram矩阵 K=[K(xi,xj)]m×n 是半正定矩阵。 ———–李航《统计学习方法》
SMO算法是一种启发式算法。其基本思路是:所有变量的解都满足KKT条件时,已经得到最优解。否则,选择2个变量(其中有一个变量必须是不满足KKT条件的),固定其它所有的变量,进行求解。不断的迭代计算,最终得到最优解。当然这里的2个变量的选择是很有讲究的。分为2层循环的选择,具体就不再叙述了。可以参考其它资料。
在《机器学习实战》书第二章给了一个手写识别系统的例子(主要是由于他提供了数据),在官网下载到数据。有2000个训练样本,900个测试样本。可下载。
和上一篇一样,我们使用weka工具。在数据转换过程中,笔者遇到了些许问题,这里需要强调一点,weka对于数据格式的要求还是比较严格的。
所有的文件(包括转换后的数据可下载,点击可下载)
原来的txt数据截图如下。
将其WEKA可以处理的格式,这个数据是32×32的数据,一共1024个数据。我将其转换成了1024个属性。并且是数字型。一共有2000多个训练样本,编写JAVA程序处理得到arff格式文件。JAVA代码参考如下。
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
public class transToArff {
@SuppressWarnings("resource")
public static void main(String[] args) throws IOException {
File dir = new File(
"/Users/arthur/Desktop/机器学习与数据挖掘/machinelearninginaction/Ch02/digits/trainingDigits");
File[] file = dir.listFiles();
FileOutputStream out = null;
out= new FileOutputStream(new File("/Users/arthur/Desktop/numbertrain.arff"));
out.write("@relation testKNN_predicted_predicted\n".getBytes());
for(int i=1;i<1025;i++){
out.write(("@attribute"+" "+i+" numeric\n").getBytes());
}
out.write("@attribute leixing {0,1,2,3,4,5,6,7,8,9}\n".getBytes());
out.write("@data\n".getBytes());
for (File f : file) {
if (f.isFile()&&!f.isHidden()) {
String res="";
BufferedReader reader = new BufferedReader(new FileReader(f));
String str = reader.readLine();
for (int k= 0; k < 32; k++) {
for (int i= 0; i < 32; i++) {
res+=str.charAt(i)+",";
}
str = reader.readLine();
}
res+=f.getName().charAt(0)+"\n";
out.write(res.getBytes());
}
}
}
}
打开WEKA,将训练数据导入,并在Classify选择Function选择 SMO算法。选择交叉验证(Flods按照默认的为10即可)。
运行,得到结果如下。
=== Stratified cross-validation ===
=== Summary ===
Correctly Classified Instances 1890 97.7249 %
Incorrectly Classified Instances 44 2.2751 %
Kappa statistic 0.9747
Mean absolute error 0.1602
Root mean squared error 0.2721
Relative absolute error 88.9941 %
Root relative squared error 90.7025 %
Coverage of cases (0.95 level) 100 %
Mean rel. region size (0.95 level) 80.3619 %
Total Number of Instances 1934
=== Detailed Accuracy By Class ===
TP Rate FP Rate Precision Recall F-Measure MCC ROC Area PRC Area Class
0.989 0.000 1.000 0.989 0.995 0.994 0.999 0.994 0
0.980 0.008 0.933 0.980 0.956 0.951 0.990 0.936 1
0.990 0.001 0.995 0.990 0.992 0.991 1.000 0.998 2
0.990 0.002 0.985 0.990 0.987 0.986 0.997 0.978 3
0.978 0.003 0.968 0.978 0.973 0.970 0.998 0.970 4
0.968 0.002 0.978 0.968 0.973 0.970 0.997 0.972 5
0.990 0.001 0.990 0.990 0.990 0.989 0.999 0.985 6
0.985 0.003 0.975 0.985 0.980 0.978 0.999 0.983 7
0.950 0.002 0.977 0.950 0.963 0.960 0.992 0.941 8
0.951 0.003 0.975 0.951 0.963 0.959 0.990 0.942 9
Weighted Avg. 0.977 0.003 0.978 0.977 0.977 0.975 0.996 0.970
=== Confusion Matrix ===
a b c d e f g h i j <-- classified as
187 0 0 0 1 0 1 0 0 0 | a = 0
0 194 0 0 0 0 0 1 2 1 | b = 1
0 1 193 0 0 0 0 0 1 0 | c = 2
0 0 0 197 0 1 0 1 0 0 | d = 3
0 2 0 0 182 0 1 0 0 1 | e = 4
0 1 1 1 1 181 0 0 1 1 | f = 5
0 2 0 0 0 0 193 0 0 0 | g = 6
0 0 0 0 1 0 0 198 0 2 | h = 7
0 6 0 0 1 2 0 0 171 0 | i = 8
0 2 0 2 2 1 0 3 0 194 | j = 9
(1)核函数选择为多项式核函数
用我们的测试数据再进行下测试。通过交叉验证得到的模型测试数据表明正确率为 98.5201 %。
=== Re-evaluation on test set ===
User supplied test set
Relation: testKNN_predicted_predicted
Instances: unknown (yet). Reading incrementally
Attributes: 1025
=== Summary ===
Correctly Classified Instances 932 98.5201 %
Incorrectly Classified Instances 14 1.4799 %
Kappa statistic 0.9835
Mean absolute error 0.1601
Root mean squared error 0.272
Coverage of cases (0.95 level) 100 %
Total Number of Instances 946
(2)核函数选择RBF函数(高斯核函数)
相对上一个,这个函数执行时间更久。但结果好了1%左右达到 98.9429 %。
交叉验证得到的结果正确率为97.4147 %,用测试数据测试正确率98.6258 %,结果与SMO算法差不多。但是用SMO预测效果更好,因为KNN算法得不到模型,但SMO算法可以。
李航,《统计学习方法》,清华大学出版社
Peter,《机器学习实战》
WEKA开发手册