我有一个带变量的数据框,比如a,b,c,d
dat <- data.frame(a=runif(1e5), b=runif(1e5), c=runif(1e5), d=runif(1e5))
并希望在每个列之间生成所有可能的双向交互项,即:ab,ac,ad,bc,bd,cd。实际上我的数据框有超过100列,所以我无法手动编码。最有效的方法是什么(注意我不想要 b和b a)?
答案 0 :(得分:12)
您打算如何处理所有这些互动条款?有几种选择,最好取决于你想要做什么。
如果您想将互动传递给lm
或aov
等建模函数,那么它非常简单,只需使用.^2
语法:
fit <- lm( y ~ .^2, data=mydf )
以上内容将调用lm
并告诉它适合mydf
中除y
之外的变量的所有主要效果和所有双向互动。
如果由于某种原因您真的想要计算所有互动,那么您可以使用model.matrix
:
tmp <- model.matrix( ~.^2, data=iris)
这将包括拦截列和主效果列,但如果您不想要它们,可以删除它们。
如果您需要与建模不同的内容,则可以在评论中使用combn
函数作为@akrun提及。
答案 1 :(得分:3)
假设预期的输出是列名的组合(来自评论,它应该是a_b
,a_c
等),我们可以在列的名称上使用combn
数据集并将m
指定为2。
combn(colnames(dat), 2, FUN=paste, collapse='_')
#[1] "a_b" "a_c" "a_d" "b_c" "b_d" "c_d"
如果我们需要在&#39; dat&#39;中乘以列的组合,我们使用列名combn
的{{1}}输出的每个元素对数据集进行子集化dat[,x[1]]
,{{1 }),乘以(dat[,x[2]]
)它,转换为&#39; data.frame&#39; (*
),通过data.frame(
列名称组合设置列名称(setNames
)。我们使用paste
在list
和cbind
列表元素中创建输出。
do.call(cbind
do.call(cbind, combn(colnames(dat), 2, FUN= function(x)
list(setNames(data.frame(dat[,x[1]]*dat[,x[2]]),
paste(x, collapse="_")) )))
# a_b a_c a_d b_c b_d c_d
#1 0.26929788 0.17697473 0.26453066 0.55676619 0.83221898 0.54691008
#2 0.06291005 0.08337501 0.04455453 0.10370775 0.05542008 0.07344851
#3 0.53789990 0.47301970 0.03112880 0.51305076 0.03376319 0.02969076
#4 0.41596384 0.34920860 0.25992717 0.53948322 0.40155468 0.33711187
#5 0.16878584 0.21232357 0.09196025 0.08162171 0.03535148 0.04447027
注意:基准测试因列数,行数而异。在这里,我使用的是OP的帖子中显示的列数。
set.seed(494)
dat <- data.frame(a=runif(1e6), b=runif(1e6), c=runif(1e6), d=runif(1e6))
greg <- function()model.matrix( ~.^2, data=dat)
akrun <- function() {do.call(cbind, combn(colnames(dat), 2, FUN= function(x)
list(setNames(data.frame(dat[,x[1]]*dat[,x[2]]),
paste(x, collapse="_")) )))}
system.time(greg())
# user system elapsed
# 1.159 0.024 1.182
system.time(akrun())
# user system elapsed
# 0.013 0.000 0.013
library(microbenchmark)
microbenchmark(greg(), akrun(), times=20L, unit='relative')
# Unit: relative
# expr min lq mean median uq max neval cld
# greg() 39.63122 38.53662 10.23198 18.81274 6.568741 4.642702 20 b
# akrun() 1.00000 1.00000 1.00000 1.00000 1.000000 1.000000 20 a
答案 2 :(得分:1)
由于model.matrix
抱怨的因素只有一个级别,因此您可能想使用stats::terms
labels(terms(~.^2, data = iris[, 1:3]))
# [1] "Sepal.Length" "Sepal.Width" "Petal.Length"
# [4] "Sepal.Length:Sepal.Width" "Sepal.Length:Petal.Length" "Sepal.Width:Petal.Length"