【问题标题】:Get all Coefficients Belonging to a Factor获取属于某个因子的所有系数
【发布时间】:2016-03-21 23:40:34
【问题描述】:

我想自动确定lm 中的哪些系数属于一个因子。所以假设我有以下模型:

d <- data.frame(a = gl(4, 2, 16), b = gl(2, 1, 16), 
                x = runif(16), y = runif(16), Y = runif(16))
l1 <- lm(Y ~ a + b + x + y, data = d)
l2 <- lm(Y ~ x + y, data = d)

那么第一个模型的系数名称如下:

names(coef(l1))
# [1] "(Intercept)" "a2"          "a3"          "a4"          "b2"         
# [6] "x"           "y"

现在理想情况下,我想要一个函数告诉我a2, a3, a4b2是虚拟编码因子的系数。

对于不包含任何因子的模型(如l2),输出应为NULL

我查看了str(l1),发现有一个插槽xlevels(如果模型中存在因子)。我可以使用names(l1$xlevels) 来获取模型中所有因子的列表,然后在系数名称上使用grep

names(coef(l1))[unlist(sapply(names(l1$xlevels), function(.) grep(., names(coef(l1)))))]
# [1] "a2" "a3" "a4" "b2"

但在我看来,这似乎是一个非常肮脏的解决方法,并且一旦我的模型中有相似的名称就不会起作用:

d$a4 <- runif(16)
l3 <- update(l1, . ~ . + a4, data = d)
names(coef(l3))[unlist(sapply(names(l3$xlevels), function(.) grep(., names(coef(l3)))))]
# [1] "a2" "a3" "a4" "a4" "b2"

此外,更改默认对比度将更改我模型中虚拟系数的名称,因此即使是处理系数名称的最精细策略也可能行不通。

长话短说:如何获得属于某个因子的所有系数的列表?

【问题讨论】:

  • l3$assign 将能够显示组以区分两个 "a4" 系数。

标签: r lm


【解决方案1】:

这里有一些方法:

1) 这假定 model.matrix 中仅包含零和一的任何列都属于一个因子(截距除外)。它适用于l1l2l3,非常短,不依赖于名称(截取除外)并且不需要摆弄lm 对象组件。它适用于主效应和交互,因为如果主效应是 0/1,那么交互也会如此。 cmets 中的l4 是一个示例,其中 0/1 假设不成立。

m <- model.matrix(l1)
all01 <- apply(m == 0 | m == 1, 2, all)
setdiff(names(all01[all01]), "(Intercept)")
## [1] "a2" "a3" "a4" "b2"

2) 这不使用名称(拦截除外),适用于 l1l2l3(以及 cmets 中的 l4)。它不对模型矩阵进行任何假设,但仅适用于仅主效应模型。 (不拦截的情况未经测试。)

cls <- attr(terms(l1), "dataClass")
intercept <- if ("(Intercept)" %in% names(coef(l1))) "" else "+ 0"
fn <- function(nm) names(coef(update(l1, paste(". ~", nm, intercept))))
setdiff(unlist(lapply(names(cls)[cls == "factor"], fn)), "(Intercept)")

【讨论】:

  • +1 非常好的方法!但是,第一个依赖于因子的参数化,如果你改变它,它可能不会起作用:
  • l4 &lt;- update(l3, contrasts = list(a = "contr.poly")) 会给你一个model.matrix,其中相关系数的条目不是0|1。对于第二种方法,这是一种非常简洁的方法,它应该适用于主效应,但对于交互作用,它并没有给出所有因子相关系数。这在原帖中没有提到,暂时不用担心,但将来可能需要。
  • 对答案中的讨论添加了限制。
  • 这适用于因子因子交互作用(0|1 不变量在那里成立),但不适用于因子变量交互作用。
  • 它会错误地检测到一个只包含 0s1s 的变量,就像在 d$false.factor &lt;- sample(0:1, 16, TRUE) 中一样
【解决方案2】:

经过cmets中卓有成效的讨论,我终于想出了这个解决方案。请注意,我略微更改了期望的结果,不仅返回分配给因子的系数,而且区分这些系数是属于因子主效应、因子-因子交互作用还是因子-变量交互作用。我将所有用例都包括在讨论之外,并且输出符合预期,是对系数的正确表征。

getCoefficientType <- function(mod) {
   INTCPT <- "(Intercept)"
   te <- mod$terms
   hasIntercept <- attr(te, "intercept") == 1
   ## factor terms
   predictors <- attr(te, "dataClasses")
   factors <- names(predictors[predictors == "factor"])
   if (hasIntercept) {
      termLabels <- c(INTCPT, attr(te, "term.labels"))
   } else {
      termLabels <- attr(te, "term.labels")
   }
   ## - loop through all terms in the model
   ## - split interactions at ":" into atoms
   ## - check if any of the atoms occurs in the factor list
   types <- sapply(strsplit(termLabels, ":"), function(x) {
      ind <- x %in% factors
      if (length(x) == 1) {
         if (x == INTCPT) {
            "intercept"
         } else if (ind) {
            "factor.main"
         } else {
            "variable.main"
         }
      } else {
         if (all(ind)) {
            "factor.factor.interaction"
         } else if (!any(ind)) {
            "variable.variable.interaction"
         } else {
            "factor.variable.interaction"
         }
      }
   })
   setNames(rep(types, rle(mod$assign)$length), names(coef(mod)))
}

d <- data.frame(a = gl(4, 2, 16), b = gl(2, 1, 16), 
                x = runif(16), y = runif(16), Y = runif(16), a4 = runif(16))
l1 <- lm(Y ~ a + b + x + y, data = d)
l2 <- lm(Y ~ x + y, data = d)
l3 <- update(l1, . ~ . + a4, data = d)
l4 <- update(l3, contrasts = list(a = "contr.poly"))
l5 <- update(l2, . ~ . + a:x + x:y)
l6 <- update(l5, . ~ . - 1)
getCoefficientType(l1)
getCoefficientType(l2)
getCoefficientType(l3)
getCoefficientType(l4)
getCoefficientType(l5)
getCoefficientType(l6)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-16
    • 2013-07-06
    • 1970-01-01
    相关资源
    最近更新 更多