заставить что-то вроде лаг работать с group_by - PullRequest
1 голос
/ 03 апреля 2020

Пытался воспроизвести мой конвейер с упрощенными данными / кодом следующим образом:

library(magrittr)
library(dplyr)
library(lubridate)

df <- data.frame(
    date = c(
        as.Date("2015-1-1")
        , as.Date("2015-2-1")
        , as.Date("2015-3-1")
        , as.Date("2015-4-1")
        , as.Date("2015-5-1")
        , as.Date("2015-6-1")

        , as.Date("2015-1-1")
        , as.Date("2015-2-1")
        , as.Date("2015-3-1")
        , as.Date("2015-4-1")
        , as.Date("2015-5-1")
        , as.Date("2015-6-1")

    )
    ,value = c(1,2,3,4,5,6 ,7,8,9,10,11,12)
    ,category = as.factor(c("cat1","cat1","cat1","cat1","cat1","cat1"  ,"cat2","cat2","cat2","cat2","cat2","cat2"))
) %>%
group_by(
    date = floor_date(date, unit = "monthly")
    ,category 
) %>%
summarise(
    value = min(value)
) %>%
mutate(
    month_minus_1 = lag(value, n=1)
    , month_minus_2 = lag(value, n=2)
) %>%
arrange(
    category 
    , value
)
df

Я добавил floor_date, чтобы указать, что я соберу некоторые цифры по месяцам и буду использовать некоторые статистические данные c (здесь мин). В любом случае, как я могу применить лаг к каждой группе, так как приведенные выше результаты неверны:

date category value month_minus_1 month_minus_2
2015-01-01  cat1    1   NA  NA
2015-02-01  cat1    2   NA  NA
2015-03-01  cat1    3   NA  NA
2015-04-01  cat1    4   NA  NA
2015-05-01  cat1    5   NA  NA
2015-06-01  cat1    6   NA  NA
2015-01-01  cat2    7   1   NA
2015-02-01  cat2    8   2   NA
2015-03-01  cat2    9   3   NA
2015-04-01  cat2    10  4   NA
2015-05-01  cat2    11  5   NA
2015-06-01  cat2    12  6   NA

Ожидаемый результат:

 date category value month_minus_1 month_minus_2
    2015-01-01  cat1    1   NA  NA
    2015-02-01  cat1    2   1   NA
    2015-03-01  cat1    3   2   1
    2015-04-01  cat1    4   3   2
    2015-05-01  cat1    5   4   3
    2015-06-01  cat1    6   5   4
    2015-01-01  cat2    7   NA  NA
    2015-02-01  cat2    8   7   NA
    2015-03-01  cat2    9   8   7
    2015-04-01  cat2    10  9   8
    2015-05-01  cat2    11  10  9
    2015-06-01  cat2    12  11  10

Ответы [ 2 ]

1 голос
/ 03 апреля 2020

summarize удаляет один «слой» группировки. Таким образом, после суммирования у вас есть df, сгруппированный только по date, а вы хотите группу по категориям.

Простое переключение двух группирующих переменных дает вам то, что вам нужно:

library(magrittr)
library(dplyr)
library(lubridate)

df %>%
  group_by(category,
           date = floor_date(date, unit = "monthly")
           ) %>%
  summarise(value = min(value)) %>%
  mutate(month_minus_1 = lag(value, n = 1),
         month_minus_2 = lag(value, n = 2)) %>%
  arrange(category,
          value)

#> # A tibble: 12 x 5
#> # Groups:   category [2]
#>    category date       value month_minus_1 month_minus_2
#>    <fct>    <date>     <dbl>         <dbl>         <dbl>
#>  1 cat1     2015-01-01     1            NA            NA
#>  2 cat1     2015-02-01     2             1            NA
#>  3 cat1     2015-03-01     3             2             1
#>  4 cat1     2015-04-01     4             3             2
#>  5 cat1     2015-05-01     5             4             3
#>  6 cat1     2015-06-01     6             5             4
#>  7 cat2     2015-01-01     7            NA            NA
#>  8 cat2     2015-02-01     8             7            NA
#>  9 cat2     2015-03-01     9             8             7
#> 10 cat2     2015-04-01    10             9             8
#> 11 cat2     2015-05-01    11            10             9
#> 12 cat2     2015-06-01    12            11            10

Создано в 2020-04-03 пакетом Представления (v0.3.0)

1 голос
/ 03 апреля 2020

Короткий ответ: date не должно быть внутри dplyr::group_by().

dplyr::group_by() создает отдельные мини-фреймы данных, которые, например, dplyr::lag(), не видны снаружи. По сути, вы создали двенадцать фреймов данных с одной строкой.

library(magrittr)
library(dplyr)
library(lubridate)

data.frame(
  date = as.Date(c(
    "2015-01-01", "2015-02-01", "2015-03-01", "2015-04-01", "2015-05-01", "2015-06-01", 
    "2015-01-01", "2015-02-01", "2015-03-01", "2015-04-01", "2015-05-01", "2015-06-01" 
  )),
  value = c(1,2,3,4,5,6 ,7,8,9,10,11,12),
  category = as.factor(c("cat1","cat1","cat1","cat1","cat1","cat1"  ,"cat2","cat2","cat2","cat2","cat2","cat2"))
) %>% 
group_by(category) %>%
mutate(
  month_minus_1 = lag(value, n=1, order_by = date),
  month_minus_2 = lag(value, n=2, order_by = date)
) %>%
ungroup() 

Результаты:

# A tibble: 12 x 5
   date       value category month_minus_1 month_minus_2
   <date>     <dbl> <fct>            <dbl>         <dbl>
 1 2015-01-01     1 cat1                NA            NA
 2 2015-02-01     2 cat1                 1            NA
 3 2015-03-01     3 cat1                 2             1
 4 2015-04-01     4 cat1                 3             2
 5 2015-05-01     5 cat1                 4             3
 6 2015-06-01     6 cat1                 5             4
 7 2015-01-01     7 cat2                NA            NA
 8 2015-02-01     8 cat2                 7            NA
 9 2015-03-01     9 cat2                 8             7
10 2015-04-01    10 cat2                 9             8
11 2015-05-01    11 cat2                10             9
12 2015-06-01    12 cat2                11            10

Я вижу, что вы хотите обобщить что-то в своем реальном сценарии (не упрощенном сценарий вы представляете здесь). Я бы сделал что-то вроде этого, где пол и характеристики рассчитываются до подстановки для лага. Этот первый dplyr::ungroup() не требуется, но мне нравится, как он лучше передает намерение.

data.frame(
  date = as.Date(c(
    "2015-01-01", "2015-02-01", "2015-03-01", "2015-04-01", "2015-05-01", "2015-06-01", 
    "2015-01-01", "2015-02-01", "2015-03-01", "2015-04-01", "2015-05-01", "2015-06-01" 
  )),
  value = c(1,2,3,4,5,6 ,7,8,9,10,11,12),
  category = as.factor(c("cat1","cat1","cat1","cat1","cat1","cat1"  ,"cat2","cat2","cat2","cat2","cat2","cat2"))
) %>%
dplyr::mutate(
  month_floor = floor_date(date, unit = "monthly")
) %>%
group_by(category, month_floor) %>%
summarize(
  value_mean   = mean(value) # Or the rollup statistic you're referring to.
) %>% 
ungroup() %>% 
group_by(category) %>%
mutate(
  month_minus_1 = lag(value_mean, n=1, order_by = month_floor),
  month_minus_2 = lag(value_mean, n=2, order_by = month_floor)
) %>%
ungroup() 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...