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

时间:2015-02-22 20:05:30

标签: r dataframe apply

我有一个包含四列的数据框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的新数据框提取出来。 lm.coef由A列和B列的因子编制索引?如何访问by的结果对象?还有另一种方法可以获得理想的结果吗?

4 个答案:

答案 0 :(得分:3)

我不是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

这可能会为您提供有关如何进一步处理它的提示。

答案 1 :(得分:2)

只是为了补充@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

答案 2 :(得分:2)

data.table方法是:

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

c用于合并/集中两个列表:as.list(coef(...))list(cor = ...)data.table automaticalls使它们成为列。

结果:

   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

答案 3 :(得分: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])))))