为了举例说明,在R中考虑一个基本的回归模型:
这个可以扩展,但它并不真正可编程,因为函数本身需要硬编码。
除了滥用
1.能够以编程方式从基本的R对象生成任意公式项
2.能够将项添加到公式中,这些项将像手动输入的项一样工作
使用方法3可以获得功能1,使用方法2可以获得功能2。是否有一种方法4 -- "中庸之道" -- 可以同时获取这两种功能?
form1 <- Petal.Length ~ Sepal.Length + Sepal.Width
fit1 <- lm(form1, iris)
(对任何在此发帖的植物学家表示歉意。)
为了添加二次项和交互项,我知道有三种方法:
1)老派的方式
逐个输入项:
form2 <- . ~ Sepal.Length*Sepal.Width + I(Sepal.Length^2) + I(Sepal.Width^2)
fit2 <- update(fit1, form2)
这种方法不适用于复杂的公式,也不能用来编程。
2) 糟糕的方法
字符串操作:
vars <- attr(terms(form1), "term.labels")
squared_terms <- sprintf("I(%s^2)", vars)
inter_terms <- combn(vars, 2, paste, collapse = "*")
form2 <- reformulate(c(inter_terms, squared_terms), ".")
这个可以扩展,但它并不真正可编程,因为函数本身需要硬编码。
3) 后门
直接操作数据。library(lazyeval)
library(dplyr)
square <- function (v) interp(~ I(v1^2), v1 = as.name(v))
inter <- function(v) interp(~ v1*v2, v1 = as.name(v[1]), v2 = as.name(v[2]))
vars <- attr(terms(form1), "term.labels")
squared_terms <- lapply(vars, square) %>%
set_names(paste0(vars, " ^2"))
inter_terms <- combn(vars, 2, inter, simplify = FALSE) %>%
set_names(combn(vars, 2, paste, collapse = " x "))
fit2 <- model.frame(fit1) %>%
mutate_(.dots = squared_terms) %>%
mutate_(.dots = inter_terms) %>%
lm(Petal.Length ~ ., data = .)
这是相当可扩展的,可以编程到变量命名。但它也有点疯狂,因为它打破了首先使用公式的目的。
我希望我能做到的
我希望我能做类似于这样的事情:
library(lazyeval)
library(dplyr)
square <- function (v) interp(~ I(v1^2), v1 = as.name(v))
inter <- function(v) interp(~ v1*v2, v1 = as.name(v[1]), v2 = as.name(v[2]))
squared_terms <- apply.formula(form1, squared_terms)
inter_terms <- combn.formula(form1, 2, inter)
fit2 <- form1 %>%
append.formula(squared_terms) %>%
append.formula(inter_terms) %>%
update(fit1, .)
除了滥用
dplyr
之外,这里有两个杀手级功能:1.能够以编程方式从基本的R对象生成任意公式项
2.能够将项添加到公式中,这些项将像手动输入的项一样工作
使用方法3可以获得功能1,使用方法2可以获得功能2。是否有一种方法4 -- "中庸之道" -- 可以同时获取这两种功能?
lm(Petal.Length ~ (Sepal.Length + Sepal.Width)^2, iris)
进行所有交互。我猜方括号里的平方部分可能会有些棘手。 - MrFlicklm
。 - rawr