总结dplyr中的条件

kev*_*kuo 40 r sqldf dplyr

我将以一个例子来说明我的问题.

样本数据:

 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
Run Code Online (Sandbox Code Playgroud)

我想要做的是通过ID总结B的总和以及当A是"foo"时B的总和.我可以通过以下几个步骤完成此操作:

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
Run Code Online (Sandbox Code Playgroud)

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

require(sqldf)
my_db <- src_sqlite("my_db.sqlite3", create = T)
df_sqlite <- copy_to(my_db, df)
Run Code Online (Sandbox Code Playgroud)

我想mutate用来定义一个新Bfoo列:

df_sqlite %>%
  mutate(Bfoo = ifelse(A=="foo", B, 0))
Run Code Online (Sandbox Code Playgroud)

不幸的是,这不适用于数据库的末端.

Error in sqliteExecStatement(conn, statement, ...) : 
  RS-DBI driver: (error in statement: no such function: IFELSE)
Run Code Online (Sandbox Code Playgroud)

eip*_*i10 72

你可以在一个dplyr声明中做两个总和:

df1 <- df %>%
  group_by(ID) %>%
  summarize(sumB = sum(B),
            sumBfoo = sum(B[A=="foo"]))
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案!以前没有遇到过这种子集:`df%>%summary(函数(colname [conditional_colname]))` (4认同)

kev*_*kuo 28

写下@ hadley的评论作为答案

df_sqlite %>%
  group_by(ID) %>%
  mutate(Bfoo = if(A=="foo") B else 0) %>%
  summarize(sumB = sum(B),
            sumBfoo = sum(Bfoo)) %>%
  collect
Run Code Online (Sandbox Code Playgroud)


Lau*_*riK 8

如果你想进行计数而不是总结,那么答案就会有所不同.代码的变化很小,特别是在条件计数部分.

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
Run Code Online (Sandbox Code Playgroud)