web-dev-qa-db-ja.com

tidyr / dplyrにゼロカウント行を追加するための適切なイディオム

次のようなカウントデータがあるとします。

library(tidyr)
library(dplyr)

X.raw <- data.frame(
    x = as.factor(c("A", "A", "A", "B", "B", "B")),
    y = as.factor(c("i", "ii", "ii", "i", "i", "i")),
    z = 1:6)
X.raw
#   x  y z
# 1 A  i 1
# 2 A ii 2
# 3 A ii 3
# 4 B  i 4
# 5 B  i 5
# 6 B  i 6

私はこのように整理して要約したいと思います:

X.tidy <- X.raw %>% group_by(x,y) %>% summarise(count=sum(z))
X.tidy
# Source: local data frame [3 x 3]
# Groups: x
#
#   x  y count
# 1 A  i     1
# 2 A ii     5
# 3 B  i    15

x=="B"およびy=="ii"欠損値ではなく、ゼロのカウントを観察しました。つまり、フィールドワーカーは実際にそこにいましたが、正のカウントがなかったため、生データに行が入力されていませんでした。これを行うことで、ゼロカウントを明示的に追加できます。

X.fill <- X.tidy %>% spread(y, count, fill=0) %>% gather(y, count, -x)
X.fill
# Source: local data frame [4 x 3]
# 
#   x  y count
# 1 A  i     1
# 2 B  i    15
# 3 A ii     5
# 4 B ii     0

しかし、それは物事を行うための少し遠回りの方法のようです。彼らはこれのためのよりきれいなイディオムですか?

明確にするために:私のコードはすでにspreadを使用し、次にgatherを使用して、私が必要とすることをすでに実行しているので、より直接的なルートwithintidyrおよびdplyr

34
pete

dplyr 0.8なので、.drop = FALSEのパラメータgroup_byを設定することで実行できます。

X.tidy <- X.raw %>% group_by(x, y, .drop = FALSE) %>% summarise(count=sum(z))
X.tidy
# # A tibble: 4 x 3
# # Groups:   x [2]
#   x     y     count
#   <fct> <fct> <int>
# 1 A     i         1
# 2 A     ii        5
# 3 B     i        15
# 4 B     ii        0
19

tidyrcomplete関数は、この状況でのみ使用できます。

ドキュメントから:

これは、expand()、left_join()、replace_naのラッパーであり、欠落しているデータの組み合わせを完成させるのに役立ちます。

2つの方法で使用できます。最初に、要約してxyのすべての組み合わせでデータセットを「完成」し、zに0を入力する前に、元のデータセットでそれを使用できます(使用できます)デフォルトのNAfillna.rm = TRUE in sum)。

X.raw %>% 
    complete(x, y, fill = list(z = 0)) %>% 
    group_by(x,y) %>% 
    summarise(count = sum(z))

Source: local data frame [4 x 3]
Groups: x [?]

       x      y count
  <fctr> <fctr> <dbl>
1      A      i     1
2      A     ii     5
3      B      i    15
4      B     ii     0

事前に要約されたデータセットでcompleteを使用することもできます。 completeはグループ化を尊重することに注意してください。 X.tidyはグループ化されているため、ungroupを使用してデータセットをxおよびyで完成させるか、各グループ内で完成させたい変数をリストすることができます。この場合はy

# Complete after ungrouping
X.tidy %>% 
    ungroup %>%
    complete(x, y, fill = list(count = 0))

# Complete within grouping
X.tidy %>% 
    complete(y, fill = list(count = 0))

結果は各オプションで同じです。

Source: local data frame [4 x 3]

       x      y count
  <fctr> <fctr> <dbl>
1      A      i     1
2      A     ii     5
3      B      i    15
4      B     ii     0
25
aosmith

Tidyrのexpandを使用して因子のレベルのすべての組み合わせを作成し、次にleft_join

X.tidy %>% expand(x, y) %>% left_join(X.tidy)

# Joining by: c("x", "y")
# Source: local data frame [4 x 3]
# 
#   x  y count
# 1 A  i     1
# 2 A ii     5
# 3 B  i    15
# 4 B ii    NA

次に、値をNAとして保持するか、値を0またはその他の値に置き換えます。この方法も問題の完全な解決策ではありませんが、spreadgatherよりも高速でRAMに優しいです。

4
inscaven

plyrには目的の機能がありますが、dplyrには(まだ)機能がないため、@ momearaで示されているように、ゼロカウントグループを含めるには追加のコードが必要です。 この質問 も参照してください。 plyr::ddply追加するだけ.drop=FALSE最終結果にゼロカウントグループを保持します。例えば:

library(plyr)

X.tidy = ddply(X.raw, .(x,y), summarise, count=sum(z), .drop=FALSE)

X.tidy
  x  y count
1 A  i     1
2 A ii     5
3 B  i    15
4 B ii     0
3
eipi10

可能なすべての組み合わせを明示的に作成し、それを整頓された要約と結合することができます。

x.fill <- expand.grid(x=unique(x.tidy$x), x=unique(x.tidy$y)) %>%
    left_join(x.tidy, by=("x", "y")) %>%
    mutate(count = ifelse(is.na(count), 0, count)) # replace null values with 0's
2
momeara