Есть ли функция R, которая может отменить cumsum() и воссоздать исходный некумулятивный столбец в наборе данных?

Для простоты я создал небольшой фиктивный набор данных.

Обратите внимание: даты указаны в формате гггг-мм-дд.

Вот набор данных DF:

DF <- tibble(country = rep(c("France", "England", "Spain"), each = 4),
             date = rep(c("2020-01-01", "2020-02-01", "2020-03-01", "2020-04-01"), times = 3),
             visits = c(10, 16, 14, 12, 11, 9, 12, 14, 13, 13, 15, 10))

# A tibble: 12 x 3
   country date       visits
   <chr>   <chr>       <dbl>
 1 France  2020-01-01     10
 2 France  2020-01-02     16
 3 France  2020-01-03     14
 4 France  2020-01-04     12
 5 England 2020-01-01     11
 6 England 2020-01-02      9
 7 England 2020-01-03     12
 8 England 2020-01-04     14
 9 Spain   2020-01-01     13
10 Spain   2020-01-02     13
11 Spain   2020-01-03     15
12 Spain   2020-01-04     10

Вот набор данных DFc:

DFc <- DF %>% group_by(country) %>% mutate(cumulative_visits = cumsum(visits))

# A tibble: 12 x 3
# Groups:   country [3]
   country date       cumulative_visits
   <chr>   <chr>                  <dbl>
 1 France  2020-01-01                10
 2 France  2020-01-02                26
 3 France  2020-01-03                40
 4 France  2020-01-04                52
 5 England 2020-01-01                11
 6 England 2020-01-02                20
 7 England 2020-01-03                32
 8 England 2020-01-04                46
 9 Spain   2020-01-01                13
10 Spain   2020-01-02                26
11 Spain   2020-01-03                41
12 Spain   2020-01-04                51

Допустим, у меня есть только набор данных DFc. Какие функции R можно использовать для воссоздания столбца посещений (как показано в наборе данных DF) и, по сути, отмены/обратного действия cumsum()?

Мне сказали, что я могу включить функцию lag(), но я не знаю, как это сделать.

Кроме того, как изменился бы код, если бы даты были разделены на несколько недель, а не на один день?

Любая помощь приветствуется :)


person Karima    schedule 19.10.2020    source источник


Ответы (2)


Начиная с вашего игрушечного примера:

library(dplyr)

DF <- tibble(country = rep(c("France", "England", "Spain"), each = 4),
             date = rep(c("2020-01-01", "2020-02-01", "2020-03-01", "2020-04-01"), times = 3),
             visits = c(10, 16, 14, 12, 11, 9, 12, 14, 13, 13, 15, 10))


DF <- DF %>% 
  group_by(country) %>% 
  mutate(cumulative_visits = cumsum(visits)) %>% 
  ungroup()

Я предлагаю вам два метода:

  1. разница
  2. отставание [как вам конкретно требовалось]
DF %>%
  group_by(country) %>%
  mutate(decum_visits1 = c(cumulative_visits[1], diff(cumulative_visits)),
         decum_visits2 = cumulative_visits - lag(cumulative_visits, default = 0)) %>% 
  ungroup()

#> # A tibble: 12 x 6
#>    country date       visits cumulative_visits decum_visits1 decum_visits2
#>    <chr>   <chr>       <dbl>             <dbl>         <dbl>         <dbl>
#>  1 France  2020-01-01     10                10            10            10
#>  2 France  2020-02-01     16                26            16            16
#>  3 France  2020-03-01     14                40            14            14
#>  4 France  2020-04-01     12                52            12            12
#>  5 England 2020-01-01     11                11            11            11
#>  6 England 2020-02-01      9                20             9             9
#>  7 England 2020-03-01     12                32            12            12
#>  8 England 2020-04-01     14                46            14            14
#>  9 Spain   2020-01-01     13                13            13            13
#> 10 Spain   2020-02-01     13                26            13            13
#> 11 Spain   2020-03-01     15                41            15            15
#> 12 Spain   2020-04-01     10                51            10            10

Если одна дата отсутствует, скажем, как в следующем примере:

DF1 <- DF %>% 
  
  # set to date!
  mutate(date = as.Date(date)) %>%
  
  # remove one date just for the sake of the example
  filter(date != as.Date("2020-02-01"))

Тогда я советую вам complete даты, а вы fill visits с нулем и cumulative_visits с последним увиденным значением. Затем вы можете получить противоположное cumsum таким же образом, как и раньше.

DF1 %>% 
  group_by(country) %>% 
  
  # complete and fill with zero!
  tidyr::complete(date = seq.Date(min(date), max(date), by = "month"), fill = list(visits = 0)) %>% 
  
  # fill cumulative with the last available value
  tidyr::fill(cumulative_visits) %>%
  
  # reset in the same way
  mutate(decum_visits1 = c(cumulative_visits[1], diff(cumulative_visits)),
         decum_visits2 = cumulative_visits - lag(cumulative_visits, default = 0)) %>% 
  ungroup()
person Edo    schedule 19.10.2020

Вот универсальное решение. Это небрежно, потому что, как вы видите, это не вернуло foo[1], но это можно исправить. (как и обращение вывода последней строки.) Я оставлю это в качестве упражнения для читателя.

foo <- sample(1:20,10)
 [1] 16 11 13  5  6 12 19 10  3  4
 bar <- cumsum(foo)
 [1] 16 27 40 45 51 63 82 92 95 99
 rev(bar[-1])-rev(bar[-length(bar)])
[1]  4  3 10 19 12  6  5 13 11
person Carl Witthoft    schedule 19.10.2020