dplyr: сохранить пустые уровни фактора, но не пустые уровни комбинации факторов, которые не отображаются в данных - PullRequest
1 голос
/ 28 мая 2019

При группировании и суммировании с помощью dplyr, как правильно сохранять пустые уровни каждого фактора группировки, но не сохранять пустые комбинации из нескольких факторов группировки?

В качестве примера рассмотрим данные, записанные в разное время на нескольких сайтах. Я мог бы отфильтровать, а затем рассчитать что-то для каждого года на каждом сайте. Я хотел бы иметь значение по умолчанию сводки для пустого вектора, если фильтр удаляет год полностью. Таким образом, сайту "a" принадлежит 10 лет, а сайту "b" - 1 год, поэтому я всегда хотел бы, чтобы в сводке было 11 строк.

Если я использую .drop = TRUE в group_by, я теряю годы:

library(dplyr)
library(zoo)
library(lubridate)

set.seed(1)

df <- data.frame(site = factor(c(rep("a", 120), rep("b", 12))),
                 date = c(seq.Date(as.Date("2000/1/1"), by = "month", length.out = 120), seq.Date(as.Date("2000/1/1"), by = "month", length.out = 12)),
                 value = rnorm(132, 50, 10))
df$year <- factor(lubridate::year(df$date))

df %>% 
  filter(value > 65) %>%
  group_by(site, year, .drop = TRUE) %>%
  summarise(f = first(date))
#> # A tibble: 6 x 3
#> # Groups:   site [1]
#>   site  year  f         
#>   <fct> <fct> <date>    
#> 1 a     2000  2000-04-01
#> 2 a     2004  2004-08-01
#> 3 a     2005  2005-01-01
#> 4 a     2007  2007-11-01
#> 5 a     2008  2008-10-01
#> 6 a     2009  2009-02-01

и с .drop = FALSE я получаю все дополнительные годы для сайта "b", которых не было в исходных данных:

df %>% 
  filter(value > 65) %>%
  group_by(site, year, .drop = FALSE) %>%
  summarise(f = first(date))
#> # A tibble: 20 x 3
#> # Groups:   site [2]
#>    site  year  f         
#>    <fct> <fct> <date>    
#>  1 a     2000  2000-04-01
#>  2 a     2001  NA        
#>  3 a     2002  NA        
#>  4 a     2003  NA        
#>  5 a     2004  2004-08-01
#>  6 a     2005  2005-01-01
#>  7 a     2006  NA        
#>  8 a     2007  2007-11-01
#>  9 a     2008  2008-10-01
#> 10 a     2009  2009-02-01
#> 11 b     2000  NA        
#> 12 b     2001  NA        
#> 13 b     2002  NA        
#> 14 b     2003  NA        
#> 15 b     2004  NA        
#> 16 b     2005  NA        
#> 17 b     2006  NA        
#> 18 b     2007  NA        
#> 19 b     2008  NA        
#> 20 b     2009  NA

Лучший способ, которым я мог придумать, это вычислить счетчики, затем объединить их, затем отфильтровать, затем отбросить переменную счетчика, но это довольно грязно. Я знаю, что .drop был добавлен только недавно к dplyr, что очень полезно для одного фактора, но есть ли еще чистый способ сделать это для нескольких факторов?

df %>% 
  filter(value > 65) %>%
  group_by(site, year, .drop = FALSE) %>%
  summarise(f = first(date)) %>%
  left_join(df %>% count(site, year, .drop = FALSE), by = c("site", "year")) %>%
  filter(n > 0) %>%
  select(-n)
#> # A tibble: 11 x 3
#> # Groups:   site [2]
#>    site  year  f         
#>    <fct> <fct> <date>    
#>  1 a     2000  2000-04-01
#>  2 a     2001  NA        
#>  3 a     2002  NA        
#>  4 a     2003  NA        
#>  5 a     2004  2004-08-01
#>  6 a     2005  2005-01-01
#>  7 a     2006  NA        
#>  8 a     2007  2007-11-01
#>  9 a     2008  2008-10-01
#> 10 a     2009  2009-02-01
#> 11 b     2000  NA

1 Ответ

1 голос
/ 28 мая 2019

Не уверен, что это то, что вам нравится.

Если вы замените даты на value < 65 на NA вместо того, чтобы отфильтровывать их, вы можете действовать как обычно.



df %>% 
  mutate(date = replace(date, value < 65, NA)) %>%
  group_by(site, year) %>%
  summarise(f = first(date[!is.na(date)]))

# A tibble: 11 x 3
# Groups:   site [2]
   site  year  f         
   <fct> <fct> <date>    
 1 a     2000  NA        
 2 a     2001  NA        
 3 a     2002  2002-03-01
 4 a     2003  NA        
 5 a     2004  NA        
 6 a     2005  NA        
 7 a     2006  2006-02-01
 8 a     2007  NA        
 9 a     2008  2008-07-01
10 a     2009  2009-02-01
11 b     2000  2000-08-01

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...