R 避免因子在测试集中具有新级别时失败
我有一个数据集,我用以下方式将其拆分为训练和测试子集:R 避免因子在测试集中具有新级别时失败,r,glm,R,Glm,我有一个数据集,我用以下方式将其拆分为训练和测试子集: train_ind <- sample(seq_len(nrow(dataset)), size=(2/3)*nrow(dataset)) train <- dataset[train_ind] test <- dataset[-train_ind] train_ind我从以下数据生成过程开始(一个二进制响应变量、一个数值自变量和三个分类自变量): 当然,predict会产生上面@Setzer22描述的消息错误: glm
train_ind <- sample(seq_len(nrow(dataset)), size=(2/3)*nrow(dataset))
train <- dataset[train_ind]
test <- dataset[-train_ind]
train_ind我从以下数据生成过程开始(一个二进制响应变量、一个数值自变量和三个分类自变量):
当然,predict
会产生上面@Setzer22描述的消息错误:
glm.res <- glm(y ~ ., data=train, family = binomial(link=logit))
preds <- predict(glm.res, test, type="response")
在子集中,测试集x2
和x3
的test
没有新的类别:
table(subset.test[,"x2"])
(0,0.2] (0.2,0.4] (0.4,0.6] (0.6,0.8] (0.8,1]
26 25 20 0 28
table(subset.test[,"x3"])
(0,0.25] (0.25,0.5] (0.5,0.75] (0.75,1]
0 29 29 41
现在,predict
工作得很好:
preds <- predict(glm.res, subset(test,filt), type="response")
head(preds)
30 39 41 49 55 56
0.7732564 0.8361226 0.7576259 0.5589563 0.8965357 0.8058025
preds感谢您的回答!在R中似乎没有简单的方法来实现这一点,这让我感到沮丧。在我看来,实现应该涵盖一个基本的边缘案例,解决方案很简单。有什么我没有考虑的吗?为什么它不能忽略任何新的值呢?说一个模型假设新的值应该被视为“0”是正确的行为是不公平的。例如,假设您有一个预测“眼睛颜色”,并且您的模型是根据只包含“棕色”和“蓝色”的数据进行训练的。如果此变量编码为brown=0和blue=1,并且您的测试数据现在包含有一个绿眼睛的人,那么按照您的建议将此行视为“0”将假定他们有棕色眼睛。更一般地说,要求模型对其在培训期间从未接触过的事物进行预测是没有意义的,这就是为什么会出现错误的原因在我的问题中有一个隐含的假设(无可否认,我应该澄清),即值0表示“缺失”或“空”值。另外请注意,我不是问如何强制一个模型(即glm函数)处理它以前从未见过的数据,而是问作为一个程序员如何解决现实场景中可能发生的R中的问题。我认为在R中用零来编码缺失值是没有意义的——它们要么被视为数字变量的“真”零(一个坏主意),要么被视为因子的自身级别。如果您想将所有缺少的值建模为它们自己的类别,则可能会出现例外情况。@jruf003我同意您的意见。我的发言只是想强调,尽管存在这种不一致性,我的问题的目的仍然有效。我问这个问题的时候,对0的值做了一些隐含的假设,这对于我当时正在做的任何项目都是有意义的(不幸的是,我不记得了!)。可能是我真正的意思是“N/A”而不是0,或者在我的特定用例中,数值0是对N/As的一个很好的猜测:例如,当数据居中并按比例缩放时,0是平均值,这对于N/As来说或多或少是一种合理的处理(即使是次优的)。
idx <- which(df$x2!="(0.6,0.8]" & df$x3!="(0,0.25]")
train_ind <- sample(idx, size=(2/3)*length(idx))
train <- df[train_ind,]
train$x2 <- droplevels(train$x2)
train$x3 <- droplevels(train$x3)
test <- df[-train_ind,]
table(train$x2)
(0,0.2] (0.2,0.4] (0.4,0.6] (0.8,1]
55 40 53 49
table(test$x2)
(0,0.2] (0.2,0.4] (0.4,0.6] (0.6,0.8] (0.8,1]
58 48 45 90 62
table(train$x3)
(0.25,0.5] (0.5,0.75] (0.75,1]
66 61 70
table(test$x3)
(0,0.25] (0.25,0.5] (0.5,0.75] (0.75,1]
131 63 47 62
glm.res <- glm(y ~ ., data=train, family = binomial(link=logit))
preds <- predict(glm.res, test, type="response")
dropcats <- function(k) {
xtst <- test[,k]
xtrn <- train[,k]
cmp.tst.trn <- (unique(xtst) %in% unique(xtrn))
if (is.factor(xtst) & any(!cmp.tst.trn)) {
cat.tst <- unique(xtst)
apply(test[,k]==matrix(rep(cat.tst[cmp.tst.trn],each=nrow(test)),
nrow=nrow(test)),1,any)
} else {
rep(TRUE,nrow(test))
}
}
filt <- apply(sapply(2:ncol(df),dropcats),1,all)
subset.test <- test[filt,]
table(subset.test[,"x2"])
(0,0.2] (0.2,0.4] (0.4,0.6] (0.6,0.8] (0.8,1]
26 25 20 0 28
table(subset.test[,"x3"])
(0,0.25] (0.25,0.5] (0.5,0.75] (0.75,1]
0 29 29 41
preds <- predict(glm.res, subset(test,filt), type="response")
head(preds)
30 39 41 49 55 56
0.7732564 0.8361226 0.7576259 0.5589563 0.8965357 0.8058025