(在R中)为什么使用用户定义的线性内核的ksvm的结果与使用“vanilladot”的ksvm的结果不同?

时间:2013-07-17 04:17:31

标签: r machine-learning svm

我想在R中使用Ksvm的用户定义内核函数 所以,我尝试制作一个vanilladot内核并与" vanilladot"进行比较。内置于" kernlab"作为练习。

我按照以下方式编写内核。

#
###vanilla kernel with class "kernel"
#
kfunction.k <- function(){
   k <- function (x,y){crossprod(x,y)}
   class(k) <- "kernel"
   k}
l<-0.1 ; C<-1/(2*l)

###use kfunction.k
tmp<-ksvm(x,factor(y),scaled=FALSE, type = "C-svc", kernel=kfunction.k(), C = C)
alpha(tmp)[[1]]
ind<-alphaindex(tmp)[[1]]
x.s<-x[ind,] ; y.s<-y[ind]
w.class.k<-t(alpha(tmp)[[1]]*y.s)%*%x.s
w.class.k

我认为这次行动的结果与以下的结果相同。 然而它没有。

#
###use "vanilladot"
#
l<-0.1 ; C<-1/(2*l)
tmp1<-ksvm(x,factor(y),scaled=FALSE, type = "C-svc", kernel="vanilladot", C = C)
alpha(tmp1)[[1]]
ind1<-alphaindex(tmp1)[[1]]
x.s<-x[ind1,] ; y.s<-y[ind1]
w.tmp1<-t(alpha(tmp1)[[1]]*y.s)%*%x.s
w.tmp1

我想这个问题可能与内核类有关。 当class设置为&#34; kernel&#34;时,会出现此问题。 但是当class被设置为&#34; vanillakernel&#34;时,使用用户定义的内核的ksvm的结果等于使用&#34; vanilladot&#34;的ksvm的结果。它是用Kernlab构建的。

#
###vanilla kernel with class "vanillakernel"
#
kfunction.v.k <- function(){
   k <- function (x,y){crossprod(x,y)}
   class(k) <- "vanillakernel"  
   k}
# The only difference between kfunction.k and kfunction.v.k is "class(k)".
l<-0.1 ; C<-1/(2*l)

###use kfunction.v.k
tmp<-ksvm(x,factor(y),scaled=FALSE, type = "C-svc", kernel=kfunction.v.k(), C = C)
alpha(tmp)[[1]]
ind<-alphaindex(tmp)[[1]]
x.s<-x[ind,] ; y.s<-y[ind]
w.class.v.k<-t(alpha(tmp)[[1]]*y.s)%*%x.s
w.class.v.k

在将课程设置为&#34; kernel&#34;时,我不明白为什么结果与&#34; vanilladot&#34;不同。

我的操作是否有错误?

1 个答案:

答案 0 :(得分:3)

首先,这似乎是一个非常好的问题!

现在到了这一点。在ksvm的源代码中,我们可以找到何时在使用用户定义的内核和内置函数之间画出一条线:

 if (type(ret) == "spoc-svc") {
            if (!is.null(class.weights)) 
                weightedC <- class.weights[weightlabels] * rep(C, 
                  nclass(ret))
            else weightedC <- rep(C, nclass(ret))
            yd <- sort(y, method = "quick", index.return = TRUE)
            xd <- matrix(x[yd$ix, ], nrow = dim(x)[1])
            count <- 0
            if (ktype == 4) 
                K <- kernelMatrix(kernel, x)
            resv <- .Call("tron_optim", as.double(t(xd)), as.integer(nrow(xd)), 
                as.integer(ncol(xd)), as.double(rep(yd$x - 1, 
                  2)), as.double(K), as.integer(if (sparse) xd@ia else 0), 
                as.integer(if (sparse) xd@ja else 0), as.integer(sparse), 
                as.integer(nclass(ret)), as.integer(count), as.integer(ktype), 
                as.integer(7), as.double(C), as.double(epsilon), 
                as.double(sigma), as.integer(degree), as.double(offset), 
                as.double(C), as.double(2), as.integer(0), as.double(0), 
                as.integer(0), as.double(weightedC), as.double(cache), 
                as.double(tol), as.integer(10), as.integer(shrinking), 
                PACKAGE = "kernlab")
            reind <- sort(yd$ix, method = "quick", index.return = TRUE)$ix
            alpha(ret) <- t(matrix(resv[-(nclass(ret) * nrow(xd) + 
                1)], nclass(ret)))[reind, , drop = FALSE]
            coef(ret) <- lapply(1:nclass(ret), function(x) alpha(ret)[, 
                x][alpha(ret)[, x] != 0])
            names(coef(ret)) <- lev(ret)
            alphaindex(ret) <- lapply(sort(unique(y)), function(x)
which(alpha(ret)[, 
                x] != 0))
            xmatrix(ret) <- x
            obj(ret) <- resv[(nclass(ret) * nrow(xd) + 1)]
            names(alphaindex(ret)) <- lev(ret)
            svindex <- which(rowSums(alpha(ret) != 0) != 0)
            b(ret) <- 0
            param(ret)$C <- C
        }

重要的部分是两件事,第一,如果我们提供ksvm我们自己的内核,那么ktype=4(而vanillakernelktype=0)所以它会产生两个变化:

  • 在用户定义的内核的情况下,计算内核矩阵而不是实际使用内核
  • tron_optim例程运行有关内核的信息

现在,在svm.cpp我们可以找到tron例程,在tron_run(从tron_optim调用)中,LINEAR内核有一个单独的优化例程

if (param->kernel_type == LINEAR)
    {
     /* lots of code here */
     while (Cpj < Cp)
       {
       totaliter += s.Solve(l, prob->x, minus_ones, y, alpha, w, 
                            Cpj, Cnj, param->eps, sii, param->shrinking, 
                            param->qpsize);
     /* lots of code here */
       }
     totaliter += s.Solve(l, prob->x, minus_ones, y, alpha, w, Cp, Cn,
                          param->eps, sii, param->shrinking, param->qpsize);
     delete[] w;
    }
else
{    
    Solver_B s;
    s.Solve(l, BSVC_Q(*prob,*param,y), minus_ones, y, alpha, Cp, Cn, 
    param->eps, sii, param->shrinking, param->qpsize);
}

如您所见,线性案例以更复杂,更详细的方式处理。有一个内部优化循环多次调用求解器。这需要对此处执行的实际优化进行深入分析,但在此步骤中,您可以通过以下方式回答您的问题:

  • 您的操作中无错误
  • kernlab的svm 有一个单独的例程,用于训练带有线性内核的SVM 基于传递给代码的内核类型,将“内核”更改为“vanillakernel” “让ksvm 认为它实际上与vanillakernel一起工作,因此执行了这个单独的优化例程
  • 实际上似乎并不是一个错误,因为线性SVM实际上与高效优化技术方面的内核版本非常不同。必须要处理的启发式和数值问题的数量非常大。因此,需要一些近似值,并可能导致不同的结果。虽然对于丰富的特征空间(如由RBF内核引起的那些),但对于简单的内核线性线性内容来说,这并不重要 - 这种简化会导致显着的输出变化。