如何用两项替换 R 公式中的一项?

How can I replace one term in an R formula with two?

我有一些类似

的东西
y ~ x + z

我想将其转换为

y ~ x_part1 + x_part2 + z

更一般地说,我想要一个函数,它接受一个公式和 returns 该公式,其中所有匹配“^x$”的术语都被 "x_part1" 和 "x_part2" 替换.这是我目前的解决方案,但感觉太笨拙了...

my.formula <- fruit ~ apple + banana
var.to.replace <- 'apple'
my.terms <- labels(terms(my.formula))
new.terms <- paste0('(', 
                    paste0(var.to.replace, 
                           c('_part1', '_part2'),
                           collapse = '+'),
                    ')')
new.formula <- reformulate(termlabels = gsub(pattern = var.to.replace,
                                             replacement = new.terms,
                                             x = my.terms),                                 
                           response = my.formula[[2]])

另外一个注意事项是输入公式可能会指定交互。

y ~ b*x + z

应该输出这些(等效)公式之一

y ~ b*(x_part1 + x_part2) + z
y ~ b + (x_part1 + x_part2) + b:(x_part1 + x_part2) + z
y ~ b + x_part1 + x_part2 + b:x_part1 + b:x_part2 + z

MrFlick 提倡使用

替换(y ~ b*x + z, 列表(x=引用(x_part1 + x_part2)))

但是当我将要修改的公式存储在变量中时,如

my.formula <- fruit ~ x + banana

这种方法似乎需要更多的按摩:

substitute(my.formula, list(x=quote(apple_part1 + apple_part2)))
# my.formula

对该方法的必要更改是:

do.call(what = 'substitute',
        args = list(apple, list(x=quote(x_part1 + x_part2))))

但是当 'x' 和 c('x_part', 'x_part2') 都存储在具有名称的变量中时,我不知道如何使用这种方法,例如var.to.replacenew.terms 以上。

如果只想修改主效应,可以减去x,然后加上两个新变量。

> f <- y ~ x + z
> update(f, .~.-x+x_part1 + x_part2)
y ~ z + x_part1 + x_part2

可以写一个递归函数来修改公式的表达式树:

replace_term <- function(f, old, new){
  n <- length(f)
  if(n > 1) {
    for(i in 1:n) f[[i]] <- Recall(f[[i]], old, new)

    return(f)
  }

  if(f == old) new else f
}

您可以使用它来修改例如交互:

> replace_term(y~x*a+z - x, quote(x), quote(x1 + x2))
y ~ (x1 + x2) * a + z - (x1 + x2)

您可以为此使用substitute函数

substitute(y ~ b*x + z, list(x=quote(x_part1 + x_part2)))
# y ~ b * (x_part1 + x_part2) + z

这里我们使用命名列表告诉R用表达式x_part1 + x_part2

替换变量x

将公式作为字符串处理怎么样?许多基础 R 模型,如 lm() 接受字符串公式(否则您始终可以使用 formula())。在这种情况下,您可以使用 gsub():

f1 <- "y ~ x + z"
f2 <- "y ~ b*x + z"

gsub("x", "(x_part1 + x_part2)", f1)
#> [1] "y ~ (x_part1 + x_part2) + z"

gsub("x", "(x_part1 + x_part2)", f2)
#> [1] "y ~ b*(x_part1 + x_part2) + z"

例如,对于mtcars数据集,假设我们要将mpg(x)替换为disp + hp(x_part1 + x_part2) :

f1 <- "qsec ~ mpg + cyl"
f2 <- "qsec ~ wt*mpg + cyl"

f1 <- gsub("mpg", "(disp + hp)", f1)
f2 <- gsub("mpg", "(disp + hp)", f2)

lm(f1, data = mtcars)
#> 
#> Call:
#> lm(formula = f1, data = mtcars)
#> 
#> Coefficients:
#> (Intercept)         disp           hp          cyl  
#>    22.04376      0.01017     -0.02074     -0.56571

lm(f2, data = mtcars)
#> 
#> Call:
#> lm(formula = f2, data = mtcars)
#> 
#> Coefficients:
#> (Intercept)           wt         disp           hp          cyl  
#>   20.421318     1.554904     0.026837    -0.056141    -0.876182  
#>     wt:disp        wt:hp  
#>   -0.006895     0.011126

根据rcorty的要求,将'x'和c('x_part','x_part2')分别存储在var.to.replacenew.terms中,并采纳 MrFlick 的建议使用 setNames,我们或许可以执行以下操作:

my.formula <- fruit ~ x + banana
var.to.replace <- "x"
new.terms <-  c('x_part', 'x_part2') 
new.terms1 <- paste(new.terms, collapse="+")
do.call("substitute", list(my.formula, setNames(list(str2lang(new.terms1)), var.to.replace))) 

> fruit ~ x_part + x_part2 + banana

顺便说一句,我发现 Paul Johnson 的 Rchaeology(第 2.1 节)具有相关性、教育性和娱乐性。