我的目标是使用交叉验证来评估线性模型的性能。
我的问题是我的训练和测试集可能并不总是具有相同的变量级别。
以下是可重现的数据示例:
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
具有三个级别(D
,E
,F
)。
在我们的数据总量中,D
的数量远远超过E
和F
的数量。
因此,只要您提取全部数据的一小部分(进行交叉验证)。
很有可能将您的z
变量全部设置为D
级别。
因此E
和F
级别被丢弃,因此我们得到了错误(此答案有助于理解问题:https://stackoverflow.com/a/51555998/10972294)。
我的问题是:如何避免掉头?
如果不可能的话,还有哪些选择?
(请记住,这是一个可复制的示例,我正在使用的实际数据具有许多变量,例如z
,我希望避免将其删除。)
答案 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>
有关统计数据的评论:如果您仅列举一些特定因素的例子,那么您期望哪种拟合方法?拟合度较差且置信范围很广。