如何调试线性模型和预测的“因子具有新水平”错误[重复]

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

还显示了traintest 的表格,表明它们具有相同的因子:

> 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

我正在拟合一个参数多于数据的模型,因此该模型排名不足(将在最后解释)。但是,这不会影响 lmpredict 的工作方式。

如果您只检查table(train$f)table(test$f),它没有用,因为问题不是由变量f 引起的,而是由x 中的NA 引起的。 lmglm 删除不完整的案例,即至少有一个 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"lmglm 将在构建模型框架(以及后来的模型矩阵)时丢弃未使用的级别:

## 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 强制由lmglm

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? 这让用户了解lmglm 在后台做了什么,并使他们的调试工作更加轻松。

注意,列表中应该还有其他推荐:

[没有。 0] 自己做子集化

用户可能偶尔会使用subset 参数。但是有一个潜在的陷阱:不是所有的因子水平都可能出现在子集数据集中,因此您以后使用predict 时可能会得到“新的因子水平”。

当您编写包装lmglm 的函数时,上述建议尤其重要。你希望你的函数是健壮的。要求您的函数返回一个信息性错误,而不是等待 lmglm 抱怨。


我们可以从拟合模型对象中获得的有用信息

lmglm 在拟合对象中返回 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 工作?

如果您不能选择使用不同的 traintest 数据集(请参阅下一节),您需要在 test 而不是 xlevels 中将这些因子水平设置为 @ 987654383@。然后predict 将只预测NA 用于此类不完整的情况。


有没有更好的方法来避免此类问题?

人们将数据拆分为traintest,因为他们想要进行交叉验证。第一步是在您的完整数据集上应用na.omit 以消除NA 噪声。然后我们可以对剩下的内容进行随机分区,但是这种天真的方式可能会以

test 中的某些因子水平,但 train 中没有 train 中的某些因子变量在移除未使用的级别后只有 1 个级别(糟糕,使用 lmglm 时出现“对比”错误)

因此,强烈建议您进行一些更复杂的分区,例如分层抽样。

其实还有一个危险,但不会导致编程错误:

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 函数可用于创建数据的平衡拆分或随机分层拆分

【讨论】:

以上是关于如何调试线性模型和预测的“因子具有新水平”错误[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何使用线性回归模型进行预测?

使用线性回归模型预测单个值时出错

线性模型 泛化优化 之 L1 L2 正则化

如何从回归模型中绘制线性和二次预测变量,同时还要控制其他变量?

如何测试线性回归是不是适合预测 [关闭]

如何从多项式拟合线性回归模型中的给定 Y 值预测 X 值?