Python中使用LibSVM的预计算核函数

11 投票
4 回答
12818 浏览
提问于 2025-04-15 20:35

我在网上搜索了大约三个小时,但还没有找到解决办法。我想给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 个回答

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

需要特别注意的是,使用预计算内核时,你不能像其他内核那样省略零项。这些零项必须明确包含在内。

8

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

17

首先,我们来了解一下核和支持向量机(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的特性。

撰写回答