почему мой оператор dplyr создает дополнительные строки? - PullRequest
1 голос
/ 10 марта 2019

Я хочу, чтобы 'temp' вывел 40 строк, состоящих из мужчин в возрасте 1-20 лет и женщин в возрасте 1-20 лет.Вместо этого он создает 40 строк, затем копирует их и добавляет их, в результате чего «temp» становится 80 строками.

Почему он это делает и как мне его остановить?Я знаю, что могу удалить строки 41-80 самостоятельно, но это сложно при работе с большими наборами данных.

library(dplyr)
library(tidyr)

gender <- sample(c("male","female"), 100, replace = T)
age <- sample(1:20, , replace = T)

df <- data.frame(gender, age)

temp <- df %>% group_by(gender, age) %>%
  summarise(count = n()) %>%
  complete(gender = c("male", "female"), age = 1:20, fill = list(count = 0))

1 Ответ

2 голосов
/ 10 марта 2019

Из dplyr виньетка (выделение добавлено):

Когда вы группируете по нескольким переменным, каждая сводка снимает один уровень группировки.

Ниже приведен фрейм данных, в который был передан ваш код complete:

> df %>% group_by(gender, age) %>% summarise(count = n()) 
# A tibble: 24 x 3
# Groups:   gender [?]
   gender   age count
   <fct>  <int> <int>
 1 female     2     4
 2 female     3     2
 3 female     7     6
 4 female     9     5
 5 female    10     4
 6 female    11     2
 7 female    12     3
 8 female    13     4
 9 female    15     1
10 female    18     1
# ... with 14 more rows

Мы можем видеть, что после одного раунда summarise фрейм данных больше не группируетсяна age, но он все еще сгруппирован по gender.Это означает, что на следующем шаге он будет пытаться завершить все комбинации пола (M / F) и возраста (1-20) в пределах каждой группы, что приведет к 40 рядам комбинацийдля каждого пола.Таким образом, с двумя полами мы получаем 40 x 2 = 80 строк.

Следующие подходы были бы эквивалентны в получении ожидаемого результата:

# explicitly remove all grouping
t1 <- df %>% 
  group_by(gender, age) %>%
  summarise(count = n()) %>%
  ungroup() %>%
  complete(gender = c("male", "female"), 
           age = 1:20, 
           fill = list(count = 0))

# retain gender grouping, & only complete for different ages within each gender group
t2 <- df %>% 
  group_by(gender, age) %>%
  summarise(count = n()) %>%
  complete(age = 1:20, 
           fill = list(count = 0))

# use count, which is a wrapper for group_by(), summarise(n = n()), & ungroup() in one line
# note: the output variable name from this approach is hard-coded to n, & there is currently
# no way to change it in this step
t3 <- df %>%
  count(gender, age) %>%
  rename(count = n) %>%
  complete(gender = c("male", "female"), 
           age = 1:20, 
           fill = list(count = 0))

> all.equal(t1, t2)
[1] TRUE
> all.equal(t1, t3)
[1] TRUE
...