Python中使用LibSVM的预计算核函数
我在网上搜索了大约三个小时,但还没有找到解决办法。我想给libsvm提供一个预先计算好的核函数来对一个数据集进行分类,但是:
我该如何生成一个预先计算好的核函数?(比如,对于鸢尾花数据,基本的预计算核函数是什么?)
在libsvm的文档中提到:
对于预计算的核函数,每个实例的第一个元素必须是ID。例如,
samples = [[1, 0, 0, 0, 0], [2, 0, 1, 0, 1], [3, 0, 0, 1, 1], [4, 0, 1, 1, 2]] problem = svm_problem(labels, samples) param = svm_parameter(kernel_type=PRECOMPUTED)
ID是什么?文档中没有进一步的说明。我可以按顺序分配ID吗?
任何关于libsvm的帮助,以及预计算核函数的例子都非常感谢。
4 个回答
这里有一个简单的包含两个类别的3维向量自定义内核输入文件,它可以正常工作。我会解释一下各个部分(不过你也可以看看StompChicken的回答):
1 0:1 1:10 2:12 3:21
2 0:2 1:12 2:19 3:30
1 0:3 1:21 2:30 3:130
每行的第一个数字表示它属于哪个类别。接下来的部分是0:n的形式,并且必须是顺序的,也就是说:
第一项是0:1
第二项是0:2
第三项是0:3
这样做的一个可能原因是,libsvm会返回与向量对应的alpha_i值,但对于预计算的内核,向量不会显示(这些向量可能非常庞大),而是显示与该向量对应的索引0:n,这样可以让你的输出更容易与输入匹配。特别是因为输出的顺序并不是你输入的顺序,而是按类别分组的。因此,当你阅读输入文件时,能够将libsvm的输出与自己的输入对应起来,看到这些0:n的值是非常有用的。这里你可以看到输出:
svm_type c_svc
kernel_type precomputed
nr_class 2
total_sv 3
rho -1.53951
label 1 2
nr_sv 2 1
SV
0.4126650675419768 0:1
0.03174528241667363 0:3
-0.4444103499586504 0:2
需要特别注意的是,使用预计算内核时,你不能像其他内核那样省略零项。这些零项必须明确包含在内。
scikit-learn在处理自定义核函数时,隐藏了libsvm的大部分细节。你可以直接传入一个任意的函数作为你的核函数,它会为你计算格拉姆矩阵,或者你也可以传入已经计算好的格拉姆矩阵。
如果你选择第一种方式,语法是:
>>> from scikits.learn import svm
>>> clf = svm.SVC(kernel=my_kernel)
这里的my_kernel就是你的核函数,然后你可以调用clf.fit(X, y),它会为你计算核矩阵。在第二种情况下,语法是:
>>> from scikits.learn import svm
>>> clf = svm.SVC(kernel="precomputed")
当你调用clf.fit(X, y)时,X必须是k(X, X)这个矩阵,其中k就是你的核函数。想了解更多细节,可以查看这个例子:
http://scikit-learn.org/stable/auto_examples/svm/plot_custom_kernel.html
首先,我们来了解一下核和支持向量机(SVM)...
如果你想为 n
个向量(无论维度是多少)预先计算一个核,你需要做的就是计算每一对样本之间的核函数。核函数接收两个向量并返回一个数值,所以你可以把预计算的核想象成一个 nxn
的数值矩阵。这个矩阵通常被称为核矩阵,有时也叫做Gram矩阵。
有很多不同的核,最简单的就是线性核(也叫点积):
sum(x_i * y_i) for i in [1..N] 其中 (x_1,...,x_N) 和 (y_1,..,y_N) 是向量
其次,来尝试解答你的问题...
关于libsvm中预计算核的文档其实写得很好...
Assume the original training data has three four-feature instances and testing data has one instance: 15 1:1 2:1 3:1 4:1 45 2:3 4:3 25 3:1 15 1:1 3:1 If the linear kernel is used, we have the following new training/testing sets: 15 0:1 1:4 2:6 3:1 45 0:2 1:6 2:18 3:0 25 0:3 1:1 2:0 3:1 15 0:? 1:2 2:0 3:1
在第二个例子中,每个向量都是核矩阵中的一行。索引为零的值是ID值,看起来只是一个顺序计数。第一个向量的索引1的值是第一个向量与自身的核函数值(也就是 (1x1)+(1x1)+(1x1)+(1x1) = 4
),第二个值是第一个向量与第二个向量的核函数值(也就是 (1x3)+(1x3)=6
)。后面的值也是这样计算的。你可以看到,核矩阵是对称的,这也是应该的,因为 K(x,y) = K(y,x)。
值得注意的是,第一组向量是以稀疏格式表示的(也就是说缺失的值是零),但核矩阵不是,并且不应该是稀疏的。我不知道为什么会这样,这似乎是libsvm的特性。