【问题标题】:R Error in model.frame.default: object is not a matrix when using lmR模型中的错误.frame.default:使用lm时对象不是矩阵
【发布时间】:2021-03-27 00:11:04
【问题描述】:

对于可重现的示例:

test <- structure(list(IDcount = c(1, 1, 1, 1, 1, 2, 2, 2, 2, 2), year = c(1, 
2, 3, 4, 5, 1, 2, 3, 4, 5), Otminus1 = c(-0.28, -0.28, -0.44, 
-0.27, 0.23, -0.03, -0.06, -0.04, 0, 0.02), N.1 = c(NA, -0.1, 
0.01, 0.1, -0.04, -0.04, -0.04, -0.04, -0.05, -0.05), N.2 = c(NA, 
NA, -0.09, 0.11, 0.06, NA, -0.08, -0.08, -0.09, -0.09), N.3 = c(NA, 
NA, NA, 0.01, 0.07, NA, NA, -0.12, -0.13, -0.13), N.4 = c(NA, 
NA, NA, NA, -0.04, NA, NA, NA, -0.05, -0.05), N.5 = c(NA, NA, 
NA, NA, NA, NA, NA, NA, NA, -0.13)), row.names = c(NA, -10L), groups = structure(list(
    IDcount = c(1, 2), .rows = structure(list(1:5, 6:10), ptype = integer(0), class = c("vctrs_list_of", 
    "vctrs_vctr", "list"))), row.names = 1:2, class = c("tbl_df", 
"tbl", "data.frame"), .drop = TRUE), class = c("grouped_df", 
"tbl_df", "tbl", "data.frame"))

results <- structure(list(IDcount = c(1, 2), N.1 = c(NA, NA), N.2 = c(NA, 
NA), N.3 = c(NA, NA), N.4 = c(NA, NA), N.5 = c(NA, NA)), row.names = c(NA, 
-2L), class = "data.frame")

我正在执行lm 回归,没有拦截嵌套 for 循环中的 data frame“测试”,并使用此代码将系数写入“结果”:

index <- colnames(test) %>% str_which("N.")

betas <- matrix(nrow=length(unique(test$IDcount)), ncol=2)
colnames(betas) <- c("Intercept", "beta")

for (j in colnames(test)[index]) {
  for (i in 1:2) {
    tmp <- test[test$IDcount==i, c("Otminus1", j)]
    if(any(colSums(!is.na(tmp)) == 0)) next
    betas[i,] <- coef(lm(Otminus1 ~ . -1, tmp))
  }
  betas <- data.frame(betas)
  results[[j]] <- betas$beta
}

这非常有效。但我现在想切换 y 和 x 变量,以便循环中的公式读取:

betas[i,] <- coef(lm(. ~ Otminus1 -1, tmp))

但是这样做时我收到以下错误消息:

Error in model.frame.default(formula = . ~ Otminus1 - 1, data = tmp, drop.unused.levels = TRUE) :   
Object is not a matrix

我试图通过介绍as.matrix来考虑这一点:

betas[i,] <- coef(lm(. ~ Otminus1 -1, as.matrix(tmp)))

但是当我这样做时,我收到了这个错误:

Error in model.frame.default(formula = . ~ Otminus1 - 1, data = as.matrix(tmp), : 
 'data' must be a data frame not matrix or an array

我找到了Error in model.frame.default(object, data, xlev = xlev) : object is not a matrix,但我无法将其应用到我的示例中。

【问题讨论】:

    标签: r loops matrix formula lm


    【解决方案1】:

    . 仅适用于公式的 RHS。原因可能是出现歧义,如果数据集中有两列以上(与您的特殊情况相反)。您可以改用reformulate,这有助于创建在lm 中使用的公式。

    for (j in colnames(test)[index]) {
      for (i in 1:2) {
        tmp <- test[test$IDcount == i, c("Otminus1", j)]
        if(any(colSums(!is.na(tmp)) == 0)) 
          betas[i, ] <- NA
        else {
          fo <- reformulate(names(tmp)[1], names(tmp)[2], intercept=FALSE)
          betas[i,] <- coef(lm(fo, tmp))
        }
      }
      betas <- data.frame(betas)
      results[[j]] <- betas$beta
    }
    
    results
    #   IDcount         N.1        N.2       N.3       N.4  N.5
    # 1       1 -0.03167421 0.07420163 0.1065183 -0.173913   NA
    # 2       2  0.64615385 1.10714286 1.1000000 -2.500000 -6.5
    

    不带 for 循环的替代解决方案

    这是一种更类似于 R 的方式,不使用 for 循环。首先,我们为自变量和 IDcounts 创建两个所需的向量。使用outer 我们paste 可能的组合由, 分隔,

    i.vars <- grep("N.", names(test), value=TRUE)
    n.IDcount <- 1:2
    combs <- outer(i.vars, n.IDcount, paste, sep=",")
    

    给出这个矩阵。

    combs
    #         [,1]    [,2]   
    # [1,] "N.1,1" "N.1,2"
    # [2,] "N.2,1" "N.2,2"
    # [3,] "N.3,1" "N.3,2"
    # [4,] "N.4,1" "N.4,2"
    # [5,] "N.5,1" "N.5,2"
    

    现在我们通过sapplycombs 循环,在, 处创建一个strsplit,将第一个值用作IV,将第二个值作为test 数据的子集。不可能的迭代会产生错误(N.5IDcount == 1 的情况),因此我们使用 tryCatch 并让代码在这种情况下抛出 NA

    res <- sapply(combs, function(v) {
      x <- el(strsplit(v, ","))
      tmp <- test[test$IDcount == x[2], ]
      tryCatch(lm(as.formula(paste0(x[1], "~ Otminus1 - 1")), tmp)$coe,
               error=function(e) NA)
    })
    

    最后我们将result 放入一个矩阵中。

    matrix(res, 2, byrow=TRUE, dimnames=list(n.IDcount, i.vars))
    #           N.1        N.2       N.3       N.4  N.5
    # 1 -0.03167421 0.07420163 0.1065183 -0.173913   NA
    # 2  0.64615385 1.10714286 1.1000000 -2.500000 -6.5
    

    【讨论】:

    • 代码通过了,但不幸的是,结果与切换x和y变量之前相同。因此,这段代码似乎仍然回归lm(Otminus ~ . -1, tmp)
    • @ConnorUhl 好像我把 x 和 y 互换了,你现在可以试试吗?
    • 我遇到了一个新问题。运行时,代码结果被写入 IDcount 为 1 的 N.5 字段,尽管没有观察到运行回归。在我以前的版本中,如果不可能进行回归,for 循环将写入“NA”。相反,代码现在正在复制先前回归的值(第 N.4 列,IDcount 1)。任何想法如何修改这个?
    • @ConnorUhl 只需将值设置为NA 而不是使用next,参见editet 版本。
    • @ConnorUhl 欢迎,另请参阅不带 for 循环的替代解决方案。
    猜你喜欢
    • 1970-01-01
    • 2016-05-30
    • 2017-02-03
    • 2018-10-29
    • 1970-01-01
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 2020-12-20
    相关资源
    最近更新 更多