Подмножество данных по окну временного интервала для каждой строки в кадре данных после использования group_by ()

У меня есть данные временного ряда с тремя столбцами: столбец значений, столбец group_var (используется для группировки) и столбец даты. Для каждой строки в кадре данных я хотел бы получить среднее значение для этой группы строк после дальнейшего разбиения на определенные временные рамки. Вот пример кода для подмножества:

df$value[df$date >= (current_row$date - 545) & df$date <= (current_row$date - 365)]

После того, как я получу это подмножество, я могу легко применить mean (), но где я застрял, так это то, как я могу заставить этот код работать с чем-то вроде этого:

df %>%
    group_by(group_var) %>%
      mutate(subset_mean = mean(df$value[df$date >= (current_row$date - 545) & df$date <= (current_row$date - 365)])
)

Проблема, которую я вижу, заключается в том, что я не думаю, что могу использовать df внутри строки mutate () после того, как сгруппирую исходный df. Также я не уверен, как я могу создать переменную current_row для ссылки на текущую строку для вычисления подмножества данных.

Изменить: добавлены данные примера и воспроизводимый код

library(dplyr)
date <- c("2016-02-03", "2016-06-14", "2016-03-15", "2017-04-16","2016-01-27", "2016-01-13", "2017-04-24", "2017-06-15")
date <- date %>% as.Date(format = "%Y-%m-%d")
val <- c(10, 20, 50, 70, 30, 44, 67, 42)
group_var <- c("A", "B", "B", "A", "B", "A", "A", "B")

df <- data.frame(date, val, group_var)
 
df %>% 
  group_by(group_var)

Добавлен пример данных / входов   —  person rstats23    schedule 12.03.2021

Чтобы подтвердить, ищете ли вы среднее значение в окне, которое было между 545 и 365 днями ранее?   —  person rstats23    schedule 12.03.2021

Да, это временные рамки, для которых я хочу разбить данные. От 545 до 365 дней до собственной даты каждой строки. Могут быть некоторые строки, в которых их подмножество не будет иметь строк, в этом случае возвращаемое subset_mean должно быть Н / Д.   —  person rstats23    schedule 12.03.2021

См. также:  Rails 3 Application / User Settings - лучшая практика?

Спасибо, я исправил это   —  person rstats23    schedule 12.03.2021

Добро пожаловать в StackOverflow, @ rstats23. Пожалуйста, подумайте о том, чтобы проголосовать за решения, которые работают для вас. Для решения, которое вы считаете наиболее привлекательным, также отметьте это решение как принятое, установив флажок. Спасибо!   —  person rstats23    schedule 13.03.2021

Понравилась статья? Поделиться с друзьями:
IT Шеф
Комментарии: 4
  1. rstats23

    Я бы посоветовал использовать для этого slider::slide_index_dbl:

    library(dplyr)
    df %>% 
      group_by(group_var) %>%
      arrange(group_var, date) %>%   # slider 0.1.5 requires the window variable to be ascending
      mutate(subset_mean = slider::slide_index_dbl(
        val, date, mean, .before = 545, .after = -365   
        # negative ".after" means the window ends before the current date
      )) %>% 
      ungroup()
    

    С обновленными данными я получаю

    #date <- c("2016-02-03", "2016-06-14", "2016-03-15", "2017-04-16","2016-01-27", "2016-01-13", "2017-04-24", "2017-06-15")
    
    
    # A tibble: 8 x 4
      date         val group_var subset_mean
      <date>     <dbl> <chr>           <dbl>
    1 2016-01-13    44 A               NaN  
    2 2016-02-03    10 A               NaN  
    3 2017-04-16    70 A                27  
    4 2017-04-24    67 A                27  
    5 2016-01-27    30 B               NaN  
    6 2016-03-15    50 B               NaN  
    7 2016-06-14    20 B               NaN  
    8 2017-06-15    42 B                33.3
    

    Спасибо, похоже, это именно то, что я ищу! person rstats23; 12.03.2021

    Если бы я добавил еще один столбец, содержащий логические значения, и хотел бы вычислить subset_mean только для строк, в которых логическое значение было ИСТИНА, как бы это сработало? Я добавил код, который я пробовал с ifelse () и case_when (), в исходный пост person rstats23; 12.03.2021

    Да ладно, я понял! person rstats23; 12.03.2021

  2. rstats23

    1) Это можно сделать с помощью самостоятельного соединения с помощью sql:

    library(sqldf)
    
    sqldf("select a.date, a.val, a.group_var, avg(b.val) as mean
      from df a
      left join df b on a.group_var = b.group_var and
        b.date between a.date - 595 and a.date - 365
      group by a.rowid")
    

    давая:

            date val group_var     mean
    1 2016-02-03  10         A       NA
    2 2016-06-14  20         B       NA
    3 2016-03-15  50         B       NA
    4 2017-04-16  70         A 27.00000
    5 2016-01-27  30         B       NA
    6 2016-01-13  44         A       NA
    7 2017-04-24  67         A 27.00000
    8 2017-06-15  42         B 33.33333
    

    2) или мы можем использовать оконные функции SQL:

    sqldf("select date, val, group_var,
      avg(val) over (partition by group_var 
                     order by date 
                     range between 595 preceding and 365 preceding) as mean
      from df"
    )
    

    давая:

            date val group_var     mean
    1 2016-01-13  44         A       NA
    2 2016-02-03  10         A       NA
    3 2017-04-16  70         A 27.00000
    4 2017-04-24  67         A 27.00000
    5 2016-01-27  30         B       NA
    6 2016-03-15  50         B       NA
    7 2016-06-14  20         B       NA
    8 2017-06-15  42         B 33.33333
    
  3. rstats23

    Lubridate представляет собой очень элегантное решение …

    library(tidyverse)
    library(lubridate)
    
    df = tibble(
      value = runif(100,1,100),
      group = rep(1:4,25),
      dt = as.Date(round(runif(100,1000,2000)), origin = "1970-01-01")
    )
    
    first_year <- interval(ymd("1972-01-01"), ymd("1972-12-31"))
    sec_year <- interval(ymd("1973-01-01"), ymd("1973-12-31"))
    furhter <- interval(ymd("1974-01-01"), ymd("1975-12-31"))
    
    df <- df %>% 
      mutate(
        range = case_when(
          dt %within% first_year ~"1972",
          dt %within% sec_year ~"1973",
          TRUE ~"1974-1975"
        )
      )
    
    mean_by_group_interval <- df %>% 
      group_by(
        group,
        range
      ) %>% 
      summarise(
        mean = mean(value)
      )
    
  4. rstats23

    Вот решение, в котором используется пакет dplyr.

    library(dplyr)
    
    date <- c("2016-02-03", "2016-06-14", "2016-03-15", "2017-04-16","2016-01-27", "2016-01-13", "2017-04-24", "2017-06-15")
    date <- date %>% as.Date(format = "%Y-%m-%d")
    val <- c(10, 20, 50, 70, 30, 44, 67, 42)
    group_var <- c("A", "B", "B", "A", "B", "A", "A", "B")
    
    df <- data.frame(date, val, group_var)
    
    
    df %>% 
      group_by(group_var) %>%
      arrange(group_var, date) %>% 
      mutate(
        # Determine if the current date - the first date of each group is between 365 and 595 days.
        match = between(date - first(date), 365, 595),
        # Count the number of dates that are not within the range described above to be used in calculating the mean.
        count_false = sum(match == FALSE),
        # Calculate the cumulative sum for rows in each group that are not within the range described above.
        sum_match_false = ifelse(match == FALSE, cumsum(val), NA),
        # Calculate the mean.
        mean_match_true = ifelse(match == TRUE, max(sum_match_false, na.rm = TRUE) / count_false, NA)
      ) %>% 
      # Return only these variables.
      select(date, val, group_var, mean_match_true)
    
    
    #>   date         val group_var mean_match_true
    #>   <date>     <dbl> <chr>               <dbl>
    #> 1 2016-01-13    44 A                    NA  
    #> 2 2016-02-03    10 A                    NA  
    #> 3 2017-04-16    70 A                    27  
    #> 4 2017-04-24    67 A                    27  
    #> 5 2016-01-27    30 B                    NA  
    #> 6 2016-03-15    50 B                    NA  
    #> 7 2016-06-14    20 B                    NA  
    #> 8 2017-06-15    42 B                    33.3
    

    Создано 12 марта 2021 года пакетом REPEX (v0.3.0)

Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: