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) |
我想到了使用
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) |
您可以在单个
1 2 3 4 | df1 <- df %>% group_by(ID) %>% summarize(sumB = sum(B), sumBfoo = sum(B[A=="foo"])) |
这是
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")) |