Подтвердить что ты не робот

Правильная идиома для добавления нулевых строк подсчета в tidyr/dplyr

Предположим, что у меня есть некоторые данные count, которые выглядят так:

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 then gather, поэтому меня интересует поиск более прямого маршрута внутри tidyr и dplyr.

4b9b3361

Ответ 1

Начиная с 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

Ответ 2

Функция complete из tidyr выполняется именно для этой ситуации.

Из документов:

Это оболочка вокруг expand(), left_join() и replace_na, которая полезно для заполнения отсутствующих комбинаций данных.

Вы можете использовать его двумя способами. Во-первых, вы можете использовать его в исходном наборе данных, прежде чем суммировать "заполнение" набора данных всеми комбинациями x и y и заполнить z 0 (вы можете использовать по умолчанию NA fill и используйте na.rm = TRUE в 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

Ответ 3

Вы можете использовать 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 или любое другое значение. Таким образом, это не полное решение проблемы, но она быстрее и удобнее для RAM, чем spread и gather.

Ответ 4

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

Ответ 5

Вы можете явно сделать все возможные комбинации, а затем присоединить его к аккуратной сводке:

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