web-dev-qa-db-ja.com

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

私がやりたいのは、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

ただし、sqliteで10 GB以上のメモリ不足データを処理するため、よりエレガントで高速な方法を探しています。

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

mutateを使用して新しいBfoo列を定義することを考えました。

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

残念ながら、これはデータベースの終わりには機能しません。

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

@hadleyのコメントを回答として書く

df_sqlite %>%
  group_by(ID) %>%
  mutate(Bfoo = if(A=="foo") B else 0) %>%
  summarize(sumB = sum(B),
            sumBfoo = sum(Bfoo)) %>%
  collect
27
kevinykuo

単一のdplyrステートメントで両方の合計を実行できます。

df1 <- df %>%
  group_by(ID) %>%
  summarize(sumB = sum(B),
            sumBfoo = sum(B[A=="foo"]))
65
eipi10

集計する代わりにカウントを行いたい場合、答えは多少異なります。特に条件付きカウント部分では、コードの変更はわずかです。

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
7
LauriK

行を合計するのではなく、行をカウントしたい場合は、関数に変数を渡すことができます:

_    df1 <- df %>%
group_by(ID) %>%
summarize(RowCountB = n(),
          RowCountBfoo = n(A=="foo"))
_

n()nrow()の両方でエラーが発生します。

0
user3116297