使用newdata进行predict.lm

5

我已经建立了一个不使用data=参数来构建的lm模型:

m1 <- lm( mdldvlp.trim$y ~  gc.pc$scores[,1] + gc.pc$scores[,2] + gc.pc$scores[,3] + 
                            gc.pc$scores[,4] + gc.pc$scores[,5] + gc.pc$scores[,6] + predict(gc.tA))

现在我想使用newdata来预测m1,并将我的新数据框命名为与上面的lm()调用中使用的变量匹配。
使用newComps作为我的新的gc.pc(就像gc.tA预测一样,使用新的数据框进行预测没有任何问题),我尝试了
newD <- data.frame( newComps[1:100,1:6] ,
                    predict(gc.tA , newdata = mdldvlp[1:100,predKept]))


names(newD) <- names(m1$coefficients)[-1]
names(newD) <- names(m1$model)[-1]

names(newD) <- c( "gc.pc$scores[, 1]" , "gc.pc$scores[, 2]" , "gc.pc$scores[, 3]" , 
                  "gc.pc$scores[, 4]" , "gc.pc$scores[, 5]" , "gc.pc$scores[, 6]" , 
                  "predict(gc.tA)" )
names(newD) <- c( "gc.pc$scores[,1]" , "gc.pc$scores[,2]" , "gc.pc$scores[,3]" , 
                  "gc.pc$scores[,4]" , "gc.pc$scores[,5]" , "gc.pc$scores[,6]" , 
                  "predict(gc.tA)" )

很遗憾,predict.lm不接受上述命名策略,并返回可怕的newdata警告以及建立m1的原始数据框中的预测结果:

Warning message:
'newdata' had 100 rows but variable(s) found have 1414 rows  

如何命名newD列,以使predict调用起作用?谢谢。

下面的代码重新创建了这个问题:

    require(rpart)

    set.seed(123)
    X <- matrix(runif(200) , 20 , 10)
    gc.pc <- princomp(X)
    y <- runif(20)
    mdldvlp.trim <- data.frame(y,X)
    names(mdldvlp.trim) <- c("y",paste("x",1:10,sep=""))
    predKept <- paste("x",1:10,sep="")

    gc.tA <- rpart( y ~ . , data = mdldvlp.trim)

    m1 <- lm( mdldvlp.trim$y ~  gc.pc$scores[,1] + gc.pc$scores[,2] + gc.pc$scores[,3] + 
                                gc.pc$scores[,4] + gc.pc$scores[,5] + gc.pc$scores[,6] + predict(gc.tA))

    mdldvlp <- data.frame(matrix(runif(2000) , 200 , 10))
    names(mdldvlp) <- predKept

    newComps <- predict( gc.pc , newdata=mdldvlp )

    newD <- data.frame( newComps[1:100,1:6] ,
                        predict(gc.tA , newdata = mdldvlp[1:100,predKept]))

# enter newD naming strategy here

    predict( m1 , newdata=newD )

4/20后续:

感谢大家的回答。我理解首先创建一个具有适当命名的预测变量的数据框将使事情变得更容易。 我明白。我的问题是,如果建模数据框确实评估为带有名称为gc.pc $ scores [,1] 等的变量的数据框,则为什么上面使用的命名“策略”在predict.lm中不起作用?换句话说,lm是否真的使用gc.pc $ scores [,1] 等来评估其建模数据框? 如果是这样,那么上面的重命名策略是否会在predict.lm中起作用呢?


能否将 mdldvlp.trim$ygc.pc$scorespredict(gc.tA) 合并成一个数据框,在创建 m1 时使用?这样,您就可以在 lm 中使用 data 参数,编写仅包含 names(data) 的公式,并避免为 newD 分配可能无效的名称。 - BenBarnes
3个回答

8
你正在滥用公式符号,这正是导致问题的原因。基本上你的公式是这样的:
m1 <- lm( mdldvlp.trim$y ~  gc.pc$scores[,1] + gc.pc$scores[,2] + 
                            gc.pc$scores[,3] + gc.pc$scores[,4] + 
                            gc.pc$scores[,5] + gc.pc$scores[,6] + 
                            predict(gc.tA))

这将评估为一个数据框,其中包含名为gc.pc$scores[,1]等变量。当您使用predict()时,它会在传递给newdata参数的对象中查找具有相同名称的变量。

理想情况下,您将创建一个数据对象,其中包含所有要包含的变量和适当的名称,例如:

fitData <- data.frame(mdldvlp.trim$y, gc.pc$scores[, 1:6], predict(gc.tA))
names(fitData) <- c("trimY", paste("scores", 1:6, sep = ""), "preds")

然后通过以下方式适配模型:

m1 <- lm(trimY ~ ., data = fitData)

提供与拟合模型时使用的名称相同的数据框架,可以从模型中进行新的预测。因此,使用您的newD:
newD <- data.frame(newComps[1:100,1:6] ,
                   predict(gc.tA , newdata = mdldvlp[1:100,predKept]))
names(newD) <- c(paste("scores", 1:6, sep = ""), "preds")

然后是 predict()

predict(m1 , newdata=newD)

完整示例

require(rpart)

set.seed(123)
X <- matrix(runif(200) , 20 , 10)
gc.pc <- princomp(X)
y <- runif(20)
mdldvlp.trim <- data.frame(y,X)
names(mdldvlp.trim) <- c("y",paste("x",1:10,sep=""))
predKept <- paste("x",1:10,sep="")

gc.tA <- rpart( y ~ . , data = mdldvlp.trim)
fitData <- data.frame(mdldvlp.trim$y, gc.pc$scores[, 1:6], predict(gc.tA))
names(fitData) <- c("trimY", paste("scores", 1:6, sep = ""), "preds")
m1 <- lm(trimY ~ ., data = fitData)
mdldvlp <- data.frame(matrix(runif(2000) , 200 , 10))
names(mdldvlp) <- predKept

newComps <- predict( gc.pc , newdata=mdldvlp )
newD <- data.frame(newComps[1:100,1:6] ,
                   predict(gc.tA , newdata = mdldvlp[1:100,predKept]))
names(newD) <- c(paste("scores", 1:6, sep = ""), "preds")
predict(m1 , newdata=newD)

如果公式评估结果是一个名为gc.pc$scores[,1]等变量的数据框,为什么使用相同的变量名称调用predict.lm会失败?数据框变量名称选择如何滥用公式符号? - M.Dimo
1
@M.Dimo 我的意思是您在公式中使用诸如obj$var之类的结构滥用了公式符号。您应该在公式中使用var,并将obj作为data参数传递。这些内容使用非标准评估规则工作;它们确定了您应该如何编写公式,以便lm()predict正常工作。如果您离开正轨,事情不起作用,您就得自己承担后果。我需要仔细查看您的示例,明确理解并解释为什么它不起作用。 - Gavin Simpson

1
我遇到了类似的问题。如果我的数据框有三个或更多变量(一个结果和两个或更多预测变量),我在按列号引用列时没有任何问题。但是,当我的数据框只有两个变量(一个结果,一个预测变量)时,R会给出很多错误,包括“'newdata' had 1 row but variables found have xx rows”。
根据盒子里的Marc的建议,我为数据框仅有两个变量的情况编写了一个特殊情况,并分配了变量名。这解决了我的问题。
为了解决这个警告,我重写了:
lr <- lm(train[ , ncol(train)] ~ ., data = train[ , -ncol(train)])

as:

if(ncol(train) == 2) {
    colnames(train) <- c('var1','var2')
    colnames(test) <- c('var1','var2')
    lr <- lm(var2 ~ var1, data = train)
} else if (ncol(train) > 2) {
    lr <- lm(train[ , ncol(train)] ~ ., data = train[ , -ncol(train)])
}

1
我曾经遇到过类似的问题 - 我认为通过给我的变量命名而不是引用列号来解决它。例如,不要使用gc.pc [,1],而是将gc.pc矩阵转换为数据框并向列添加名称(“PC1”,“PC2”等)。然后确保您的newdata也使用这些名称(也在数据框中)。

感谢大家的回答。我明白首先创建一个拥有适当命名预测变量的数据框会使事情更容易。我理解这一点。我的问题是,如果建模数据框确实评估为具有变量命名gc.pc$scores[,1]等的数据框,那么我如何使用它来运行predict.lm? - M.Dimo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接