7

我正在尝试使用kernlabR 包来做支持向量机(SVM)。对于我非常简单的示例,我有两条训练数据。A和B。

(A 和 B 属于类型matrix- 它们是图的邻接矩阵。)

所以我写了一个函数,它接受 A+B 并生成一个核矩阵。

> km
         [,1]     [,2]
[1,] 14.33333 18.47368
[2,] 18.47368 38.96053

现在我使用kernlab'sksvm函数来生成我的预测模型。现在,我只是想让这该死的东西发挥作用——我不担心训练错误等。

那么,问题 1:我是否正确生成了我的模型?合理吗?

# y are my classes. In this case, A is in class "1" and B is in class "-1"
> y
[1]  1 -1

> model2 =  ksvm(km, y, type="C-svc", kernel = "matrix");
> model2
Support Vector Machine object of class "ksvm" 

SV type: C-svc  (classification) 
 parameter : cost C = 1 

[1] " Kernel matrix used as input."

Number of Support Vectors : 2 

Objective Function Value : -0.1224 
Training error : 0 

到现在为止还挺好。我们创建了自定义内核矩阵,然后使用该矩阵创建了 ksvm 模型。我们将训练数据标记为“1”和“-1”。

现在预测:

> A
     [,1] [,2] [,3]
[1,]    0    1    1
[2,]    1    0    1
[3,]    0    0    0

> predict(model2, A)
Error in as.matrix(Z) : object 'Z' not found

哦哦。这没关系。有点期待,真的。“预测”需要某种向量,而不是矩阵。

所以让我们尝试一些事情:

> predict(model2, c(1))
Error in as.matrix(Z) : object 'Z' not found
> predict(model2, c(1,1))
Error in as.matrix(Z) : object 'Z' not found
> predict(model2, c(1,1,1))
Error in as.matrix(Z) : object 'Z' not found
> predict(model2, c(1,1,1,1))
Error in as.matrix(Z) : object 'Z' not found
> predict(model2, km)
Error in as.matrix(Z) : object 'Z' not found

上面的一些测试是荒谬的,但这就是我的观点:无论我做什么,我都无法让 predict() 查看我的数据并进行预测。标量不起作用,向量不起作用。2x2 矩阵不起作用,3x3 矩阵也不起作用。

我在这里做错了什么?

(一旦我弄清楚 ksvm想要什么,那么我就可以确保我的测试数据能够以理智/合理/数学上合理的方式符合该格式。)

4

4 回答 4

23

如果您考虑支持向量机如何“使用”内核矩阵,您会发现您无法以您尝试的方式真正做到这一点(如您所见 :-)

当我第一次使用 kernlab + 内核矩阵时,我实际上对此有点挣扎......巧合的是,它也适用于图形内核!

无论如何,让我们首先意识到,由于 SVM 不知道如何计算你的核函数,它需要在你的新(测试)示例和它在训练步骤中选择作为支持向量的示例之间已经计算出这些值.

因此,您需要一起计算所有示例的内核矩阵。您稍后将通过在适当时从内核矩阵中删除行+列来训练一些并测试其他一些。让我用代码告诉你。

我们可以使用ksvm文档中的示例代码来为我们的工作区加载一些数据:

library(kernlab)
example(ksvm)

您需要按几 (2) 次 return 才能绘制绘图,然后让示例完成,但您现在应该在工作区中有一个名为K. 我们需要恢复y它应该用于其标签的向量(因为它已被示例中的其他代码践踏):

y <- matrix(c(rep(1,60),rep(-1,60)))

现在,选择一部分示例用于测试

holdout <- sample(1:ncol(K), 10)

从现在开始,我将:

  1. 创建一个trainK从原始K内核矩阵命名的训练内核矩阵。
  2. 从我的训练集中创建一个 SVM 模型trainK
  3. 使用从模型中找到的支持向量来创建一个测试核矩阵testK……这是奇怪的部分。如果您查看代码kernlab以了解它如何使用支持向量索引,您就会明白为什么要这样做。可能可以用另一种方式来做这件事,但我没有看到任何关于使用内核矩阵进行预测的文档/示例,所以我在这里“艰难地”做这件事。
  4. 使用 SVM 预测这些特征并报告准确性

这是代码:

trainK <- as.kernelMatrix(K[-holdout,-holdout])  # 1
m <- ksvm(trainK, y[-holdout], kernel='matrix')  # 2
testK <- as.kernelMatrix(K[holdout, -holdout][,SVindex(m), drop=F]) # 3
preds <- predict(m, testK)  # 4
sum(sign(preds) == sign(y[holdout])) / length(holdout) # == 1 (perfect!)

那应该差不多了。祝你好运!

对以下评论的回应

K[-holdout,-holdout] 是什么意思?(“-”是什么意思?)

假设您有一个 vector x,并且您想从中检索元素 1、3 和 5,您可以:

x.sub <- x[c(1,3,5)]

如果您想检索x 元素 1、3 和 5 之外的所有内容,您可以:

x.sub <- x[-c(1,3,5)]

所以返回除了我们想要保留的行之外K[-holdout,-holdout]的所有行和列。K

as.kernelMatrix 的参数是什么——尤其是 [,SVindex(m),drop=F] 参数(这很奇怪,因为看起来整个括号都是 K 的矩阵索引?)

是的,我将两个命令内联为一个:

testK <- as.kernelMatrix(K[holdout, -holdout][,SVindex(m), drop=F])

现在您已经训练了模型,您想为它提供一个带有测试示例的新内核矩阵。K[holdout,]只会为您提供与 中的训练示例相对应的行K,以及 中的所有列K

SVindex(m)为您提供原始训练矩阵中支持向量的索引——请记住,那些行/列已holdout被删除。因此,为了使这些列索引正确(即引用正确的 sv 列),我必须首先删除这些holdout列。

无论如何,也许这更清楚:

testK <- K[holdout, -holdout]
testK <- testK[,SVindex(m), drop=FALSE]

现在testK只有我们的测试示例的行和对应于支持向量的列。testK[1,1]将在您的第一个测试示例和第一个支持向量之间计算内核函数的值。testK[1,2]将在您的第一个测试示例和第二个支持向量之间具有核函数值,等等。

更新 (2014-01-30) 以回答来自@wrahool 的评论

自从我玩这个已经有一段时间了,所以细节kernlab::ksvm有点生疏,但原则上这应该是正确的:-) ...这里是:

有什么意义testK <- K[holdout, -holdout]-您不是要删除与测试集相对应的列吗?

是的。简短的回答是,如果你想predict使用核矩阵,你必须提供一个维度为 的rows矩阵support vectors。对于矩阵的每一行(您要预测的新示例),列中的值只是在该示例和支持向量之间评估的内核矩阵的值。

调用返回原始训练数据SVindex(m)维度中给定的支持向量的索引。

所以,首先做testK <- K[holdout, -holdout]给了我一个testK矩阵,其中包含我想要预测的示例的行,并且列来自模型训练的相同示例(维度)。

我进一步对testKby的列进行子集化SVindex(m),只给我(现在)对应于我的支持向量的列。如果我没有完成第一次[, -holdout]选择,则返回的索引SVindex(m)可能与正确的示例不对应(除非N您的所有测试示例都是N矩阵的最后一列)。

另外, drop = FALSE 条件到底是做什么的?

这是一种防御性编码,以确保执行索引操作后,返回的对象与被索引的对象类型相同。

在 R 中,如果您仅索引 2D(或更高(?))对象的一个​​维度,则返回一个较低维度的对象。我不想传递一个numeric向量,predict因为它想要一个matrix

例如

x <- matrix(rnorm(50), nrow=10)

class(x)
[1] "matrix"

dim(x)
[1] 10  5

y <- x[, 1]

class(y)
[1] "numeric"

dim(y)
NULL

data.frames等也会发生同样的情况。

于 2009-11-18T16:42:50.603 回答
2

首先,我没有太多使用kernlab。但只需查看文档,我确实看到了该predict.ksvm()方法的工作示例。复制和粘贴,并省略打印到屏幕:

 ## example using the promotergene data set
 data(promotergene)

 ## create test and training set
 ind <- sample(1:dim(promotergene)[1],20)
 genetrain <- promotergene[-ind, ]
 genetest <- promotergene[ind, ]

 ## train a support vector machine
 gene <-  ksvm(Class~.,data=genetrain,kernel="rbfdot",\
               kpar=list(sigma=0.015),C=70,cross=4,prob.model=TRUE)

 ## predict gene type probabilities on the test set
 genetype <- predict(gene,genetest,type="probabilities")

这看起来很简单:使用随机抽样来生成训练集genetrain 及其补码genetest,然后通过拟合并ksvm调用predict()使用拟合的方法,以及匹配格式的新数据。这是非常标准的。

您可能会发现Max Kuhn的caret包很有用。它为各种回归、分类和机器学习方法和包(包括kernlab )提供了一个通用的评估和测试框架,并包含几个小插曲和一篇JSS 论文

于 2009-11-18T03:17:18.320 回答
2

Steve Lianoglou 是对的。

在 kernlab 中,它有点连线,并且在预测时需要每个测试示例和支持向量之间的输入内核矩阵。你需要自己找到这个矩阵。

例如,一个测试矩阵 [nxm],其中 n 是测试样本的数量,m 是学习模型中支持向量的数量(按 SVindex(model) 的顺序排列)。

示例代码

trmat <- as.kernelMatrix(kernels[trainidx,trainidx])
tsmat <- as.kernelMatrix(kernels[testidx,trainidx])

#training
model = ksvm(x=trmat, y=trlabels, type = "C-svc", C = 1)

#testing
thistsmat = as.kernelMatrix(tsmat[,SVindex(model)])
tsprediction = predict(model, thistsmat, type = "decision")

kernels 是输入核矩阵。trainidx 和 testidx 是用于训练和测试的 id。

于 2014-05-18T16:36:51.757 回答
0

从解决方案的元素自己构建标签。使用这种替代预测方法,它采用 ksvm 模型 (m) 和原始训练格式的数据 (d)

predict.alt <- function(m, d){
  sign(d[, m@SVindex] %*% m@coef[[1]] - m@b)
}

K 是kernelMatrix用于训练的。出于验证的目的,如果您predict.alt在训练数据上运行,您会注意到备用预测器方法会在 ksvm 返回的拟合值旁边切换值。本机预测器以意想不到的方式表现:

aux <- data.frame(fit=kout@fitted, native=predict(kout, K), alt=predict.alt(m=kout, d=as.matrix(K))) 
sample_n(aux, 10)
    fit  native alt
1     0       0  -1
100   1       0   1
218   1       0   1
200   1       0   1
182   1       0   1
87    0       0  -1
183   1       0   1
174   1       0   1
94    1       0   1
165   1       0   1
于 2015-03-04T05:52:33.127 回答