如何解决交叉验证glm中的错误“因数具有新水平”?

时间:2019-09-13 12:56:12

标签: r

我的目标是使用交叉验证来评估线性模型的性能。

我的问题是我的训练和测试集可能并不总是具有相同的变量级别。

以下是可重现的数据示例:

set.seed(1)
x <- rnorm(n = 1000)
y <- rep(x = c("A","B"), times = c(500,500))
z <- rep(x = c("D","E","F"), times = c(997,2,1))

data <- data.frame(x,y,z)

summary(data)

现在让我们建立一个glm模型:

model_glm <- glm(x~., data = data)

让我们在此模型上使用交叉验证:

library(boot)
cross_validation_glm <- cv.glm(data = data, glmfit = model_glm, K = 10)

这是您将得到的错误输出:

Error in model.frame.default(Terms, newdata, na.action = na.action, xlev = object$xlevels) : 
  factor z has new levels F

如果没有出现此错误,请重新运行交叉验证,并在某个时候出现类似的错误。

问题的本质在于,当您进行交叉验证时,训练和测试子集可能没有完全相同的变量级别。在这里,我们的变量z具有三个级别(DEF)。

在我们的数据总量中,D的数量远远超过EF的数量。

因此,只要您提取全部数据的一小部分(进行交叉验证)。

很有可能将您的z变量全部设置为D级别。

因此EF级别被丢弃,因此我们得到了错误(此答案有助于理解问题:https://stackoverflow.com/a/51555998/10972294)。

我的问题是:如何避免掉头?

如果不可能的话,还有哪些选择?

(请记住,这是一个可复制的示例,我正在使用的实际数据具有许多变量,例如z,我希望避免将其删除。)

1 个答案:

答案 0 :(得分:1)

要在评论中回答您的问题,我不知道是否有功能。很可能有一个,但是我不知道哪个包将包含它。对于此示例,此功能应起作用:

set.seed(1)
x <- rnorm(n = 1000)
y <- rep(x = c("A","B"), times = c(500,500))
z <- rep(x = c("D","E","F"), times = c(997,2,1))
data <- data.frame(x,y,z)

#optional tag row for later identification: 
#data$rowid<-1:nrow(data)

stratified <- function(df, column, percent){
  #split dataframe into groups based on column
  listdf<-split(df, df[[column]])
  testsubgroups<-lapply(listdf, function(x){
    #pick the number of samples per group, round up.
    numsamples <- ceiling(percent*nrow(x))
    #selects the rows
    whichones <-sample(1:nrow(x), numsamples, replace = FALSE)
    testsubgroup <-x[whichones,] 
  })  
  #combine the subgroups into one data frame
  testgroup<-do.call(rbind, testsubgroups)
  testgroup
}

testgroup<-stratified(data, "z", 0.8)

这只会按z列拆分初始数据,如果您有兴趣按多列分组,则可以使用dplyr软件包中的group_by函数进行扩展,但这是另一个问题。 / p>

有关统计数据的评论:如果您仅列举一些特定因素的例子,那么您期望哪种拟合方法?拟合度较差且置信范围很广。