【问题标题】:predict.glm() with three new categories in the test data (r)(error)predict.glm() 与测试数据中的三个新类别 (r)(error)
【发布时间】:2016-09-15 08:49:08
【问题描述】:

我有一个名为 data 的数据集,它有 481 092 行。

我将data 分成两半:

  1. 前半部分(第 1 行:240 546)称为train,用于glm()
  2. 后半部分(第 240 547 : 481 092 行)称为test,应用于验证模型;

然后我开始回归:

testreg <- glm(train$returnShipment ~ train$size + train$color + train$price + 
               train$manufacturerID + train$salutation + train$state +
               train$age + train$deliverytime, 
               family=binomial(link="logit"), data=train)

现在预测:

prediction <- predict.glm(testreg, newdata=test, type="response")

给我一​​个错误:

Error in model.frame.default(Terms, newdata, na.action=na.action, xlev=object$xlevels):
Factor 'train$manufacturerID' has new levels 125, 136, 137

现在我知道这些级别在回归中被省略了,因为它没有显示这些级别的任何系数。

我试过这个:predict.lm() with an unknown factor level in test data。但它不知何故对我不起作用,或者我可能只是不知道如何实现它。我想预测因二进制变量,但当然只能使用现有系数。上面的链接建议告诉 R 具有新级别的行应该被称为/或被视为 NA。

我该如何继续?

Z. Li 的编辑建议方法

我在第一步遇到了问题:

xlevels <- testreg$xlevels$manufacturerID
mID125 <- xlevels[1]

但是mID125NULL!我做错了什么?

【问题讨论】:

    标签: r glm lm predict categorical-data


    【解决方案1】:

    固定效应建模中,包括线性模型和广义线性模型,不可能得到新的因子水平的估计。 glm(以及lm)记录模型拟合过程中呈现和使用的因子水平,可以在testreg$xlevels中找到。

    您的模型估计公式为:

    returnShipment ~ size + color + price + manufacturerID + salutation + 
                     state + age + deliverytime
    

    然后predict 抱怨manufactureID 的新因子水平为 125、136、137。这意味着,这些级别不在testreg$xlevels$manufactureID 内,因此没有相关的预测系数。在这种情况下,我们必须删除这个因子变量并使用预测公式:

    returnShipment ~ size + color + price + salutation + 
                     state + age + deliverytime
    

    但是,标准的predict 例程无法采用您自定义的预测公式。通常有两种解决方案:

    1. testreg中提取模型矩阵和模型系数,并通过矩阵向量乘法手动预测我们想要的模型项。这就是您帖子中给出的the link 的建议;
    2. test中的因子级别重置为testreg$xlevels$manufactureID中出现的任意一个级别,例如testreg$xlevels$manufactureID[1]。因此,我们仍然可以使用标准predict 进行预测。

    现在,让我们首先选择一个用于模型拟合的因子水平

    xlevels <- testreg$xlevels$manufacturerID
    mID125 <- xlevels[1]
    

    然后我们将这个级别分配给您的预测数据:

    replacement <- factor(rep(mID125, length = nrow(test)), levels = xlevels)
    test$manufacturerID <- replacement
    

    我们已经准备好预测:

    pred <- predict(testreg, test, type = "link")  ## don't use type = "response" here!!
    

    最后,我们通过减去因子估计来调整这个线性预测器:

    est <- coef(testreg)[paste0(manufacturerID, mID125)]
    pred <- pred - est
    

    最后,如果要在原始尺度上进行预测,则应用链接函数的逆函数:

    testreg$family$linkinv(pred)
    

    更新:

    您抱怨在尝试上述解决方案时遇到了各种麻烦。这就是原因。

    您的代码:

    testreg <- glm(train$returnShipment~ train$size + train$color + 
                   train$price + train$manufacturerID + train$salutation + 
                   train$state + train$age + train$deliverytime,
                   family=binomial(link="logit"), data=train)
    

    是指定模型公式的一种非常糟糕的方法。 train$returnShipment等,将获取变量的环境严格限制在数据框train,你以后用其他数据集预测会有问题,比如test

    作为此类缺陷的一个简单示例,我们模拟一些玩具数据并拟合 GLM:

    set.seed(0); y <- rnorm(50, 0, 1)
    set.seed(0); a <- sample(letters[1:4], 50, replace = TRUE)
    foo <- data.frame(y = y, a = factor(a))
    toy <- glm(foo$y ~ foo$a, data = foo)  ## bad style
    
    > toy$formula
    foo$y ~ foo$a  
    > toy$xlevels
    $`foo$a`
    [1] "a" "b" "c" "d"
    

    现在,我们看到所有内容都带有前缀 foo$。预测期间:

    newdata <- foo[1:2, ]  ## take first 2 rows of "foo" as "newdata"
    rm(foo)  ## remove "foo" from R session
    predict(toy, newdata)
    

    我们得到一个错误:

    eval(expr, envir, enclos) 中的错误:找不到对象 'foo'

    好的风格是指定从函数的data参数获取数据的环境:

    foo <- data.frame(y = y, a = factor(a))
    toy <- glm(y ~ a, data = foo)
    

    然后foo$ 消失。

    > toy$formula
    y ~ a
    > toy$xlevels
    $a
    [1] "a" "b" "c" "d"
    

    这可以解释两件事:

    1. 您在评论中向我抱怨说,当您执行testreg$xlevels$manufactureID 时,您会得到NULL
    2. 您发布的预测错误

      Error in model.frame.default(Terms, newdata, na.action=na.action, xlev=object$xlevels):
      Factor 'train$manufacturerID' has new levels 125, 136, 137
      

      抱怨train$manufacturerID 而不是test$manufacturerID

    【讨论】:

    • 谢谢。但我不想删除整个因子变量,而只是删除(制造商 ID)级别 125、136 和 137。我可以像这样使用你的第一行代码:mID125
    • 好吧,也许我误解了你或因素变量这个词。所以变量manufacturerID的125、136和137级没有在glm()中使用,但存在于测试数据部分(你称之为newdata)。
    • 对不起,我不完全理解。这就是为什么它不起作用。我将编辑我的问题,让您知道我做得好吗?
    • 好的,我写了我到目前为止所做的。也许您可以使用正确的代码以及更多解释来编辑问题中的“编辑”部分。欢迎尽可能简单:D R 对我来说是新的,英语不是我的第一语言:D
    • @Zheyuan_Li 当然是的。我会将其发布在编辑下方的答案中
    【解决方案2】:

    由于您根据行数划分了 traintest 样本,因此您的变量的某些因子水平在训练样本和测试样本中的表现并不相同。

    您需要进行分层抽样,以确保训练和测试样本都具有所有因子级别的表示。使用 splitstackshape 包中的 stratified

    【讨论】:

      猜你喜欢
      • 2017-01-04
      • 2023-04-05
      • 1970-01-01
      • 2013-01-30
      • 1970-01-01
      • 2018-11-19
      • 1970-01-01
      • 2014-07-11
      • 2020-01-19
      相关资源
      最近更新 更多