predict.glm()在测试数据中有三个新类别(r)(错误)

时间:2016-05-18 17:48:45

标签: r glm lm predict categorical-data

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

我将data分成两半:

  1. 前半部分(第1行:240 546)被称为train,用于glm();
  2. 第二半(第240 547:481 092行)被称为test,应该用于验证模型;
  3. 然后我开始回归:

    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!我做错了什么?

2 个答案:

答案 0 :(得分:4)

固定效应建模中,包括线性模型和广义线性模型,无法估计新因子水平。 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进行预测。
  3. 现在,让我们首先选择用于模型拟合的因子水平

    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)中的错误:object&#39; foo&#39;找不到

    好的方式是指定从函数的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

答案 1 :(得分:3)

由于您已根据rownumbers对traintest样本进行了划分,因此您的变量的某些因子级别在列车和测试样本中均未得到相同的表示。

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