如何调试线性模型和预测的“因子具有新水平”错误[重复]
Posted
技术标签:
【中文标题】如何调试线性模型和预测的“因子具有新水平”错误[重复]【英文标题】:how to debug "factor has new levels" error for linear model and prediction [duplicate] 【发布时间】:2019-01-04 05:44:03 【问题描述】:我正在尝试按如下方式制作和测试线性模型:
lm_model <- lm(Purchase ~., data = train)
lm_prediction <- predict(lm_model, test)
这会导致以下错误,指出Product_Category_1
列的值存在于test
数据框中但不存在于train
数据框中):
因素 Product_Category_1 有新的级别 7、9、14、16、17、18
但是,如果我检查这些,它们肯定会出现在两个数据框中:
> nrow(subset(train, Product_Category_1 == "7"))
[1] 2923
> nrow(subset(test, Product_Category_1 == "7"))
[1] 745
> nrow(subset(train, Product_Category_1 == "9"))
[1] 312
> nrow(subset(test, Product_Category_1 == "9"))
[1] 92
还显示了train
和test
的表格,表明它们具有相同的因子:
> table(train$Product_Category_1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
110820 18818 15820 9265 118955 16159 2923 89511 312 4030 19113 3108 4407 1201 4991 7730 467 2430
> table(test$Product_Category_1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
27533 4681 4029 2301 29637 4005 745 22621 92 1002 4847 767 1033 299 1212 1967 100 645
>
【问题讨论】:
table(train$Product_Category_1)
和 table(test$Product_Category_1)
告诉你什么?如果没有可重现的示例,我们无能为力。
table(train$Product_Category_1)
和 table(test$Product_Category_1)
表明它们具有相同的因素(已编辑帖子)
仍然需要一个可重现的例子。阅读:***.com/questions/5963269/…
一种可能性是其他变量中的NA
值。 lm
应用 na.omit
,从而可以删除特定因子水平的所有观察结果。
【参考方案1】:
目录:
一个简单的演练示例 给用户的建议 我们可以从拟合模型对象中获得的有用信息 好的,我知道现在是什么问题,但是如何让predict
工作?
有没有更好的方法可以完全避免此类问题?
一个简单的演练示例
这里有一个足够简单的可重复的例子来提示你发生了什么。
train <- data.frame(y = runif(4), x = c(runif(3), NA), f = factor(letters[1:4]))
test <- data.frame(y = runif(4), x = runif(4), f = factor(letters[1:4]))
fit <- lm(y ~ x + f, data = train)
predict(fit, newdata = test)
#Error in model.frame.default(Terms, newdata, na.action = na.action, xlev = object$xlevels) :
# factor f has new levels d
我正在拟合一个参数多于数据的模型,因此该模型排名不足(将在最后解释)。但是,这不会影响 lm
和 predict
的工作方式。
如果您只检查table(train$f)
和table(test$f)
,它没有用,因为问题不是由变量f
引起的,而是由x
中的NA
引起的。 lm
和 glm
删除不完整的案例,即至少有一个 NA
的行(参见 ?complete.cases
)用于模型拟合。他们必须这样做,否则 QR 分解的底层 FORTRAN 例程将失败,因为它无法处理 NA
。如果你查看?lm
的文档,你会看到这个函数有一个参数na.action
,默认为na.omit
。您也可以将其设置为na.exclude
,但na.pass
保留NA
会导致FORTRAN 错误:
fit <- lm(y ~ x + f, data = train, na.action = na.pass)
#Error in lm.fit(x, y, offset = offset, singular.ok = singular.ok, ...) :
# NA/NaN/Inf in 'x'
让我们从训练数据集中删除NA
。
train <- na.omit(train)
train$f
#[1] a b c
#Levels: a b c d
f
现在有一个未使用的级别 "d"
。 lm
和 glm
将在构建模型框架(以及后来的模型矩阵)时丢弃未使用的级别:
## source code of lm; don't run
mf$drop.unused.levels <- TRUE
mf[[1L]] <- quote(stats::model.frame)
mf <- eval(mf, parent.frame())
这是用户无法控制的。原因是如果包含一个未使用的级别,它将在模型矩阵中生成一列零。
mf <- model.frame(y ~ x + f, data = train, drop.unused.levels = FALSE)
model.matrix(y ~ x + f, data = mf)
# (Intercept) x fb fc fd
#1 1 0.90021178 0 0 0
#2 1 0.10188534 1 0 0
#3 1 0.05881954 0 1 0
#attr(,"assign")
#[1] 0 1 2 2 2
#attr(,"contrasts")
#attr(,"contrasts")$f
#[1] "contr.treatment"
这是不希望的,因为它会为虚拟变量 fd
生成 NA
系数。由drop.unused.levels = TRUE
强制由lm
和glm
:
mf <- model.frame(y ~ x + f, data = train, drop.unused.levels = TRUE)
model.matrix(y ~ x + f, data = mf)
# (Intercept) x fb fc
#1 1 0.90021178 0 0
#2 1 0.10188534 1 0
#3 1 0.05881954 0 1
#attr(,"assign")
#[1] 0 1 2 2
#attr(,"contrasts")
#attr(,"contrasts")$f
#[1] "contr.treatment"
fd
不见了,并且
mf$f
#[1] a b c
#Levels: a b c
现在不存在的"d"
级别将导致predict
中出现“新因子级别”错误。
给用户的建议
强烈建议所有用户在拟合模型时手动执行以下操作:
[没有。 1] 删除不完整的案例; [没有。 2] 降低未使用的因子水平。这正是这里推荐的过程:How to debug "contrasts can be applied only to factors with 2 or more levels" error? 这让用户了解lm
和glm
在后台做了什么,并使他们的调试工作更加轻松。
注意,列表中应该还有其他推荐:
[没有。 0] 自己做子集化用户可能偶尔会使用subset
参数。但是有一个潜在的陷阱:不是所有的因子水平都可能出现在子集数据集中,因此您以后使用predict
时可能会得到“新的因子水平”。
当您编写包装lm
或glm
的函数时,上述建议尤其重要。你希望你的函数是健壮的。要求您的函数返回一个信息性错误,而不是等待 lm
和 glm
抱怨。
我们可以从拟合模型对象中获得的有用信息
lm
和 glm
在拟合对象中返回 xlevels
值。它包含实际用于模型拟合的因子水平。
fit$xlevels
#$f
#[1] "a" "b" "c"
因此,如果您没有遵循上面列出的建议并且在因子水平方面遇到问题,那么应该首先检查这个xlevels
。
如果您想使用 table
之类的东西来计算每个因子水平有多少个案例,这里有一种方法:Get number of data in each factor level (as well as interaction) from a fitted lm or glm [R],尽管制作模型矩阵可能会占用大量 RAM。
好的,我知道现在是什么问题,但是如何让predict
工作?
如果您不能选择使用不同的 train
和 test
数据集(请参阅下一节),您需要在 test
而不是 xlevels
中将这些因子水平设置为 @ 987654383@。然后predict
将只预测NA
用于此类不完整的情况。
有没有更好的方法来避免此类问题?
人们将数据拆分为train
和test
,因为他们想要进行交叉验证。第一步是在您的完整数据集上应用na.omit
以消除NA
噪声。然后我们可以对剩下的内容进行随机分区,但是这种天真的方式可能会以
test
中的某些因子水平,但 train
中没有
train
中的某些因子变量在移除未使用的级别后只有 1 个级别(糟糕,使用 lm
和 glm
时出现“对比”错误);
因此,强烈建议您进行一些更复杂的分区,例如分层抽样。
其实还有一个危险,但不会导致编程错误:
train
的模型矩阵秩不足(糟糕,使用predict
时,我们收到“秩不足模型的预测可能具有误导性”警告)。
关于模型拟合中的rank-deficiency,请参阅lme4::lmer reports "fixed-effect model matrix is rank deficient", do I need a fix and how to?rank-deficiency不会对模型估计和检查造成问题,但可能会对预测造成危害:R lm
, Could anyone give me an example of the misleading case on “prediction from a rank-deficient”?但是,这样的问题更难避免,尤其是当你有很多因素并且可能与交互时。
【讨论】:
或者用多重插补在训练数据集中填充 NA 可能是避免问题的另一种方法。【参考方案2】:Examples of poor binning
有点不清楚您的数据是什么样的,您应该使用预测变量图来更好地了解您正在处理的内容。下面是一个例子,说明缺陷是如何成为一般问题的。
当您将计数数据分解为因子时,您需要确保没有退化类。 IE。该类的演示文稿不为零或接近零。在班级级别上使用条形图。您会在图像中注意到,在该数据集如何拆分为虚拟类方面,有几个类存在问题。如果这是收集数据的方式,那么您会遇到丢失的数据,您可以尝试使用 K-最近邻插补,但如果丢失的数据太多,那么您可能必须重新收集数据,如果它研究数据(重做实验,重新观察过程等)。如果数据不可重现,您将需要删除该预测变量并注释您的发现以告知您的受众。
【讨论】:
欢迎来到 SO Thomas J Childers !您的情节看起来不错且相关,最好使用使用的代码回答并将情节包含在您的答案中。您可以使用reprex
包来执行此操作。【参考方案3】:
见https://www.r-bloggers.com/2016/08/data-splitting/
caret 包的 createDataPartition 函数可用于创建数据的平衡拆分或随机分层拆分
【讨论】:
以上是关于如何调试线性模型和预测的“因子具有新水平”错误[重复]的主要内容,如果未能解决你的问题,请参考以下文章