R: Добавить значение из предыдущей строки по группе, если разница дат меньше 7 - PullRequest
3 голосов
/ 06 ноября 2019

У меня есть вопрос, который каким-то образом объединяет эти два вопроса ( Вычитать дату из предыдущей строки по группе (используя R) и вычитать значение из предыдущей строки по группе ). Но не может заставить скрипт работать.

У меня есть набор данных, который выглядит примерно так:

id  |     date    |  min  
 1  |  2015-07-18 |  25
 1  |  2015-07-22 |  15
 1  |  2015-07-23 |  10
 1  |  2015-07-30 |  15
 2  |  2015-07-10 |  10
 2  |  2015-07-16 |  20
 2  |  2015-07-23 |  10

И я хочу создать новый столбец totmin, который добавляет общее количество минут, сыгранных за последние 7 дней, по id:

id  |     date    |  min  |  totmin
 1  |  2015-07-18 |  25   |    25
 1  |  2015-07-22 |  15   |    40
 1  |  2015-07-23 |  10   |    50
 1  |  2015-07-30 |  15   |    25
 2  |  2015-07-10 |  10   |    10
 2  |  2015-07-16 |  20   |    30
 2  |  2015-07-23 |  10   |    30

Я пытался с lag, но не как ограничить только 7 днями.

Ответы [ 2 ]

4 голосов
/ 06 ноября 2019

Мы можем group_by id и sum min значение для каждого date в течение 7 дней.

library(dplyr)

df %>%
  group_by(id) %>%
  mutate(totmin = purrr::map_dbl(date, ~sum(min[between(date, . - 7, .)])))

#     id  date         min totmin
#   <int> <date>     <int>  <dbl>
#1     1 2015-07-18    25     25
#2     1 2015-07-22    15     40
#3     1 2015-07-23    10     50
#4     1 2015-07-30    15     25
#5     2 2015-07-10    10     10
#6     2 2015-07-16    20     30
#7     2 2015-07-23    10     30

data

df <- structure(list(id = c(1L, 1L, 1L, 1L, 2L, 2L, 2L), date = structure(c(16634, 
16638, 16639, 16646, 16626, 16632, 16639), class = "Date"), min = c(25L, 
15L, 10L, 15L, 10L, 20L, 10L)), row.names = c(NA, -7L), class = "data.frame")
1 голос
/ 06 ноября 2019

Это можно сделать, используя fuzzyjoin:

library(dplyr)
df <- tribble(
    ~id, ~date, ~min,
    1, "2015-07-18", 25,
    1, "2015-07-22", 15,
    1, "2015-07-23", 10,
    1, "2015-07-30", 15,
    2, "2015-07-10", 10,
    2, "2015-07-16", 20,
    2, "2015-07-23", 10
  ) %>% 
  mutate(date = as.Date(date))

Мы объединим df с собой по id и date, выбрав строки из второго df, где id то же самое, а вторая date находится между первой датой и первой датой - 7.

library(fuzzyjoin)

df_join <-
  fuzzy_left_join(
    df, df,
    by = c("id", "date"),
    match_fun = c(
      "id" = `==`,
      "date" = function(x, y) {y <= x & y >= x - 7}
    )
  )

df_join
#> # A tibble: 13 x 6
#>     id.x date.x     min.x  id.y date.y     min.y
#>    <dbl> <date>     <dbl> <dbl> <date>     <dbl>
#>  1     1 2015-07-18    25     1 2015-07-18    25
#>  2     1 2015-07-22    15     1 2015-07-18    25
#>  3     1 2015-07-22    15     1 2015-07-22    15
#>  4     1 2015-07-23    10     1 2015-07-18    25
#>  5     1 2015-07-23    10     1 2015-07-22    15
#>  6     1 2015-07-23    10     1 2015-07-23    10
#>  7     1 2015-07-30    15     1 2015-07-23    10
#>  8     1 2015-07-30    15     1 2015-07-30    15
#>  9     2 2015-07-10    10     2 2015-07-10    10
#> 10     2 2015-07-16    20     2 2015-07-10    10
#> 11     2 2015-07-16    20     2 2015-07-16    20
#> 12     2 2015-07-23    10     2 2015-07-16    20
#> 13     2 2015-07-23    10     2 2015-07-23    10

Теперь нам нужно сгруппировать по идентификатору и первой дате и вычислить общее количество минут.

res <- 
  df_join %>% 
  select(id = id.x, date = date.x, min.x, min.y) %>% 
  group_by(id, date) %>% 
  summarise(min = first(min.x), totmin = sum(min.y))
res
#> # A tibble: 7 x 4
#> # Groups:   id [2]
#>      id date         min totmin
#>   <dbl> <date>     <dbl>  <dbl>
#> 1     1 2015-07-18    25     25
#> 2     1 2015-07-22    15     40
#> 3     1 2015-07-23    10     50
#> 4     1 2015-07-30    15     25
#> 5     2 2015-07-10    10     10
#> 6     2 2015-07-16    20     30
#> 7     2 2015-07-23    10     30
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...