如何将函数应用于由其他一些列聚合的数据框的多个列?

How to apply a function to multiple columns of a data frame aggregated by some other columns?

我有一个包含四列的数据框 df,例如

A  B  C  D
x  a  1  3
x  a  3  4
x  b  5  5
x  b  6  8
y  a  6  5
y  a  8  9
y  b  7  0
y  b  4  2

我想按 A 列和 B 列聚合此数据框,然后为 C 列和 D 列上的每个组应用一个函数。这样的函数可能是 cor,另一个可能是 lm .结果应该看起来像

A  B  cor/lm.coef
x  a  ...    
x  b  ...
y  a  ...
y  b  ...

我找到了一种更接近预期结果的方法:通过函数 by:

by(df, c("A", "B"), function(x) cor(x$C, x$D))
by(df, c("A", "B"), function(x) lm(C ~ D, data = x))

我的问题:我可以将所需结果提取为新数据框,其中 cor resp。 lm.coef 是由 A 列和 B 列的因子索引的?如何访问 by 的结果对象?有没有其他方法可以得到想要的结果?

我不是 by() 的忠实粉丝。我会用 split()lapply() 来解决这个任务。

do.call(rbind, lapply(split(df, list(df$A, df$B)),
   function(d) {
      l <- lm(C~D, data=d)$coef
      data.frame(A=d$A[1], B=d$B[1], COR=cor(d$C, d$D), LM1=l[1], LM2=l[2])
   }
))

这给出:

    A B COR       LM1        LM2
x.a x a   1 -5.000000  2.0000000
y.a y a   1  3.500000  0.5000000
x.b x b   1  3.333333  0.3333333
y.b y b  -1  7.000000 -1.5000000

对了,by()返回的对象其实是一个矩阵:

x <- by(df, list(df$A, df$B), function(x) cor(x$C, x$D))
unclass(x)
#   a  b
# x 1  1
# y 1 -1

这可能会提示您如何进一步处理它。

只是为了补充@gagolews 的回答,这里是 dplyr 版本

txt <- 'A  B  C  D
x  a  1  3
x  a  3  4
x  b  5  5
x  b  6  8
y  a  6  5
y  a  8  9
y  b  7  0
y  b  4  2'
df <- read.table(text = txt, header = TRUE)


library(dplyr)
df %>%
  group_by(A, B) %>%
  do(mod = lm(C ~ D, data = .), cor = with(., cor(C, D))) %>%
  do(data_frame(
      A = .$A,
      B = .$B,
      cor = .$cor,
      lm1 = coef(.$mod)[1],
      lm2 = coef(.$mod)[2])
     )

##   A B cor     lm1      lm2
## 1 x a   1 -5.0000  2.00000
## 2 x b   1  3.3333  0.33333
## 3 y a   1  3.5000  0.50000
## 4 y b  -1  7.0000 -1.50000

data.table 方法是:

require(data.table)
setDT(df)
df[,c(as.list(coef(lm(C~D))), list(cor = cor(C, D))), by=.(A,B)]

c用于combine/concentrate两个列表:as.list(coef(...))list(cor = ...)data.table automaticals 使它们成为列。

结果:

   A B (Intercept)          D cor
1: x a   -5.000000  2.0000000   1
2: x b    3.333333  0.3333333   1
3: y a    3.500000  0.5000000   1
4: y b    7.000000 -1.5000000  -1
# Expanding on your solution
x2<-df
#your code
mycor<-with(x2,by(x2[,3:4],interaction(A,B),cor))
myreg<-with(x2,by(x2,interaction(A,B),function(x)lm(C~D,data=x)))

#extra line
myreg_coef<-do.call(rbind,lapply(unique(interaction(x2$A,x2$B)),
        function(x) cbind(group=x,corr=mycor[[x]][2],t(data.frame(myreg[[x]][1])))))