关于r:汇总同一调用中的所有组值和条件子集

 2021-04-09 

Summarize all group values and a conditional subset in the same call

我将通过一个例子来说明我的问题。

样本数据:

1
2
3
4
5
6
7
8
9
10
 df <- data.frame(ID = c(1, 1, 2, 2, 3, 5), A = c("foo","bar","foo","foo","bar","bar"), B =     c(1, 5, 7, 23, 54, 202))

df
  ID   A   B
1  1 foo   1
2  1 bar   5
3  2 foo   7
4  2 foo  23
5  3 bar  54
6  5 bar 202

我要做的是通过ID总结B的总和以及当A为" foo"时B的总和。我可以通过几个步骤来做到这一点,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
require(magrittr)
require(dplyr)

df1 <- df %>%
  group_by(ID) %>%
  summarize(sumB = sum(B))

df2 <- df %>%
  filter(A =="foo") %>%
  group_by(ID) %>%
  summarize(sumBfoo = sum(B))

left_join(df1, df2)

  ID sumB sumBfoo
1  1    6       1
2  2   30      30
3  3   54      NA
4  5  202      NA

但是,我正在寻找一种更优雅/更快的方法,因为我正在处理10gb sqlite中的内存不足数据。

1
2
3
require(sqldf)
my_db <- src_sqlite("my_db.sqlite3", create = T)
df_sqlite <- copy_to(my_db, df)

我想到了使用mutate来定义新的Bfoo列:

1
2
df_sqlite %>%
  mutate(Bfoo = ifelse(A=="foo", B, 0))

不幸的是,这不适用于数据库。

1
2
Error in sqliteExecStatement(conn, statement, ...) :
  RS-DBI driver: (error in statement: no such function: IFELSE)


您可以在单个dplyr语句中进行两个加法运算:

1
2
3
4
df1 <- df %>%
  group_by(ID) %>%
  summarize(sumB = sum(B),
            sumBfoo = sum(B[A=="foo"]))

这是data.table版本:

1
2
3
4
5
6
7
8
9
library(data.table)

dt = setDT(df)

dt1 = dt[ , .(sumB = sum(B),
              sumBfoo = sum(B[A=="foo"])),
          by = ID]

dt1
1
2
3
4
5
   ID sumB sumBfoo
1:  1    6       1
2:  2   30      30
3:  3   54       0
4:  5  202       0


写出@hadley的评论作为答案

1
2
3
4
5
6
df_sqlite %>%
  group_by(ID) %>%
  mutate(Bfoo = if(A=="foo") B else 0) %>%
  summarize(sumB = sum(B),
            sumBfoo = sum(Bfoo)) %>%
  collect


如果您想进行计数而不是汇总,则答案有所不同。代码更改很小,尤其是在条件计数部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
df1 <- df %>%
    group_by(ID) %>%
    summarize(countB = n(),
              countBfoo = sum(A=="foo"))

df1
Source: local data frame [4 x 3]

  ID countB countBfoo
1  1      2         1
2  2      2         2
3  3      1         0
4  5      1         0

如果您想对行进行计数而不是求和,可以将变量传递给函数:

1
2
3
4
    df1 <- df %>%
group_by(ID) %>%
summarize(RowCountB = n(),
          RowCountBfoo = n(A=="foo"))

n()nrow()都出现错误。