7

我正在尝试使用 R 中引导库中的交叉验证 cv.glm 函数来确定应用 glm 逻辑回归时错误分类的数量。

该函数具有以下签名:

cv.glm(data, glmfit, cost, K)

前两个表示数据和模型,K 表示 k 折。我的问题是成本参数定义为:

成本:两个向量参数的函数,指定交叉验证的成本函数。成本的第一个参数应该对应于观察到的响应,第二个参数应该对应于广义线性模型的预测或拟合响应。cost 必须返回一个非负的标量值。默认值为均方误差函数。

我想对于分类来说,有一个返回错误分类率的函数是有意义的,例如:

nrow(subset(data, (predict >= 0.5  & data$response == "no") | 
                  (predict <  0.5  & data$response == "yes")))

这当然甚至在语法上都不正确。

不幸的是,我有限的 R 知识让我浪费了很多时间,我想知道是否有人能指出我正确的方向。

4

4 回答 4

8

听起来您最好只使用cost?cv.glm. 引用该部分:

 # [...] Since the response is a binary variable an
 # appropriate cost function is
 cost <- function(r, pi = 0) mean(abs(r-pi) > 0.5)

这基本上完成了您尝试对示例进行的操作。0用and替换你的“no”和“yes” 1,假设你有两个向量,predictand response。然后cost()很好地设计了它们并返回平均分类率:

## Simulate some reasonable data
set.seed(1)
predict <- seq(0.1, 0.9, by=0.1)
response <-  rbinom(n=length(predict), prob=predict, size=1)
response
# [1] 0 0 0 1 0 0 0 1 1

## Demonstrate the function 'cost()' in action
cost(response, predict)
# [1] 0.3333333  ## Which is right, as 3/9 elements (4, 6, & 7) are misclassified
                 ## (assuming you use 0.5 as the cutoff for your predictions).

我猜这其中最棘手的一点就是让你的思想完全围绕将函数作为参数传递的想法。(至少对我来说,在最长的时间里,这是使用引导包最困难的部分,这需要在相当多的地方移动。)


添加于 2016-03-22:

cost()在我看来,上面给出的函数是不必要的混淆;以下替代方法完全相同,但以更具表现力的方式:

cost <- function(r, pi = 0) { 
        mean((pi < 0.5) & r==1 | (pi > 0.5) & r==0)
}
于 2013-05-30T03:35:29.793 回答
3

我将尝试用简单的语言来解释成本函数。让我们 cv.glm(data, glmfit, cost, K)一步一步地论证:

  1. data 数据包含许多观察结果。把它想象成一系列数字甚至。

  2. glmfit 它是广义线性模型,在上述系列上运行。但是有一个问题,它将数据分成等于 K 的几个部分。并分别glmfit在每个部分上运行(测试集),将其余部分作为训练集。的输出glmfit是由与传递的拆分输入相同数量的元素组成的系列。

  3. cost 成本函数。它需要两个参数,第一个是拆分输入系列(测试集),第二个是glmfit测试输入的输出。默认为均方误差函数。 MSE 函数. 它对观察到的数据点和预测的数据点之间的差异平方求和。在函数内部,一个循环在测试集上运行(输出和输入应该具有相同数量的元素)计算差异,将其平方并添加到输出变量。

  4. K 输入应拆分到的数字。默认提供留一交叉验证。

从您的成本函数描述来看。您的 input(x) 将是一组介于 0 和 1 之间的数字(0-0.5 = no 和 0.5-1 = yes),而 output(y) 是“yes”或“no”。因此观察(x)和预测(y)之间的误差(e)将是:

cost<- function(x, y){
  e=0
  for (i in 1:length(x)){
    if(x[i]>0.5)
    {
      if( y[i]=='yes') {e=0}
      else {e=x[i]-0.5}
    }else
    {
      if( y[i]=='no') {e=0}
      else {e=0.5-x[i]}
    }
    e=e*e #square error
  }
  e=e/i #mean square error
  return (e)
}

资料来源:http ://www.cs.cmu.edu/~schneide/tut5/node42.html

于 2013-05-31T06:45:39.483 回答
2

如果您更喜欢默认的平均平方误差,则可以选择定义成本函数。如果您想这样做,那么您将编写一个函数,该函数使用两个输入返回您想要最小化的成本:(1)您正在预测的已知标签的向量,以及(2)来自您的模型的预测概率向量对于那些相应的标签。因此,对于(我认为)您在帖子中描述的成本函数,您正在寻找一个函数,该函数将返回准确分类的平均数量,如下所示:

cost <- function(labels,pred){
 mean(labels==ifelse(pred > 0.5, 1, 0))
}

定义该函数后,您可以将其传递给您的glm.cv()调用。尽管除非您有理由,否则我不建议您使用自己的成本函数而不是默认函数。您的示例不可重现,因此这是另一个示例:

> library(boot)
> 
> cost <- function(labels,pred){
+   mean(labels==ifelse(pred > 0.5, 1, 0))
+ }
> 
> #make model
> nodal.glm <- glm(r ~ stage+xray+acid, binomial, data = nodal)
> #run cv with your cost function
> (nodal.glm.err <- cv.glm(nodal, nodal.glm, cost, nrow(nodal)))
$call
cv.glm(data = nodal, glmfit = nodal.glm, cost = cost, K = nrow(nodal))

$K
[1] 53

$delta
[1] 0.8113208 0.8113208

$seed
  [1]         403         213 -2068233650  1849869992 -1836368725 -1035813431  1075589592  -782251898
...
于 2013-05-30T03:37:59.343 回答
1

示例中定义的成本函数cv.glm明确假设预测是概率,这需要type="response"函数中的参数predict。library(boot) 中的文档应明确说明这一点。否则我将被迫假设type="link"在函数内部使用默认值cv.glm,在这种情况下,成本函数将无法按预期工作。

于 2020-12-07T16:17:42.317 回答