【问题标题】:How to edit interactions in model matrix used by predict.lm()?如何编辑 predict.lm() 使用的模型矩阵中的交互?
【发布时间】:2021-08-30 11:57:53
【问题描述】:

我想编辑 R 中 predict.lm() 使用的模型矩阵来预测主效应,而不是交互作用(但使用包含交互作用的完整模型的系数和方差)。

我试过了:

data(npk) #example data
mod <- lm(yield ~ N*P*K, data=npk, x=T) #run model
newmat <- mod$x # acquire model matrix
newmat[, c(5:8)] <- 0 #set interaction terms to 0
#try to predict on the new matrix..
predict(mod, as.data.frame(newmat), type="response", interval="confidence") 

...但这会返回错误'data' must be a data.frame, not a matrix or an array,因为 predict.lm() 不接受模型矩阵。

如何使用示例代码中给出的模型矩阵进行预测?

(或者有没有更好的方法来预测主效应而不是相互作用,使用完整模型yield ~ N*P*K?)

【问题讨论】:

    标签: r lm predict


    【解决方案1】:

    我们可以手动计算交互;首先创建术语trms,然后在eval(parse()) 方法中评估它们,从而轻松完成。

    ## create interaction terms 
    iv <- c('N', 'P', 'K')  ## indp. vars
    trms <- unlist(sapply(2:3, function(m) combn(iv, m, FUN=paste, collapse='x')))
    ## evaluate them to a matrix
    Ia <- with(npk1, sapply(trms, function(x) eval(parse(text=gsub('x', '*', x)))))
    

    然后只需 cbind 并在lm() 中使用,比较:

    ## cbind
    npk2 <- cbind(npk1, Ia)
    ## following yield the same:
    (mod1 <- lm(yield ~ .^3, data=npk1))
    (mod2 <- lm(yield ~ ., data=npk2, x=TRUE))
    

    那么你可以按照你的方法:

    newmat <- mod2$x  ## acquire model matrix
    newmat[, c(5:8)] <- 0  ## set interaction terms to 0
    predict(mod2, newdata=as.data.frame(newmat))  ## newdata w/ Ia to zero
    # 1        2        3        4        5        6        7        8        9       10 
    # 54.90000 66.66667 51.43333 64.33333 63.76667 67.23333 52.00000 54.33333 54.33333 67.23333 
    # 11       12       13       14       15       16       17       18       19       20 
    # 63.76667 52.00000 63.76667 67.23333 52.00000 54.33333 66.66667 51.43333 64.33333 54.90000 
    # 21       22       23       24 
    # 64.33333 66.66667 54.90000 51.43333 
    

    鉴于:

    predict(mod1)  ## old model
    # 1        2        3        4        5        6        7        8        9       10 
    # 50.50000 57.93333 51.43333 54.66667 63.76667 54.36667 52.00000 54.33333 54.33333 54.36667 
    # 11       12       13       14       15       16       17       18       19       20 
    # 63.76667 52.00000 63.76667 54.36667 52.00000 54.33333 57.93333 51.43333 54.66667 50.50000 
    # 21       22       23       24 
    # 54.66667 57.93333 50.50000 51.43333 
        
    

    数据:

    npk1 <- structure(list(N = c(0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 
    0, 0, 1, 0, 1, 0, 1, 1, 0, 0), P = c(1, 1, 0, 0, 0, 1, 0, 1, 
    1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0), K = c(1, 0, 
    0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 
    0), yield = c(49.5, 62.8, 46.8, 57, 59.8, 58.5, 55.5, 56, 62.8, 
    55.8, 69.5, 55, 62, 48.8, 45.5, 44.2, 52, 51.5, 49.8, 48.8, 57.2, 
    59, 53.2, 56)), row.names = c(NA, 24L), class = "data.frame")
    

    【讨论】:

    • @corn_bunting 你说得对,我们这里需要更重的火炮,见更新。请注意,我在下面创建了新的 npk1 数据,因为我了解到它们只是示例,不需要因素。
    • 太棒了,这行得通!所以看起来诀窍是将每个交互明确指定为模型中的一个术语,所以当predict.lm() 到达newdata 并查找模型术语中存在的列名时,它会找到所有这些。谢谢!
    • 刚刚注意到,如果模型中存在具有多个级别的因子(当我选择示例数据时没有考虑到这一点,哎呀!),这并不容易转换。如果可以轻松调整代码以便对因素具有普遍性,那将很方便......至少我认为我现在可以让它工作我理解模型公式和newdata 之间的关系:-)
    • @corn_bunting 您是否尝试将您的因子转换为数字:stackoverflow.com/a/3418192/6574038
    • 啊,这也是一种选择。不过,我找到了 model.matrix() 函数 - 请参阅下面添加的答案。如果代码笨拙,请随意编辑我的代码。
    【解决方案2】:

    使用@jay.sf 的回答,我还设法创建了一个版本,如果模型中有多个级别的因素,则该版本可以工作:

    ##full model (using block as a multi-level factor):
    data(npk) 
    mod1 <- lm(yield ~ N*block, data=npk, x=T)
    
    ## get model formula and use it to generate the model matrix:
    predgrid <- data.frame(model.matrix(mod1, data=npk)) 
    
    ## make a new dataframe using the model matrix and the response,
    ## and run the model using all columns in the new dataframe as terms:
    npk2 <- as.data.frame(cbind(npk$yield, predgrid[, -1])) 
    colnames(npk2)[1] <- "yield" 
    mod2 <- lm(yield~., data=npk2)
    
    ## extract the model matrix dataframe again, to modify for predictions:
    newmat <- predgrid[, -1]
    colnames(newmat)
    newmat[, 7:11] <- 0
    
    ## predict on modified matrix dataframe:
    pred <- predict(mod2, newdata=newmat, type="response", interval="confidence")
    head(pred) ##
    #    fit      lwr      upr
    #1 48.15 41.18475 55.11525
    #2 59.90 52.93475 66.86525
    #3 48.15 41.18475 55.11525
    #4 59.90 52.93475 66.86525
    #5 67.50 55.43584 79.56416
    #6 67.50 55.43584 79.56416
    
    

    【讨论】:

    • 不错的解决方案,我刚刚向你借了我的空格键 ;)
    • 如果这对任何人有用:&lt;- 0 可以替换为 lapply(newmat[, 7:11],FUN=mean) 以平均交互而不是忽略它们。
    猜你喜欢
    • 2017-06-23
    • 2021-12-19
    • 1970-01-01
    • 2021-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多