将 dplyr:lag() 与不完整的时间序列数据一起使用

Using dplyr:lag() with patchy time series data

我有一些类似于以下的时间序列数据:

df <- data.frame(id = c("001","001","001","002", "003","003","003","003", 
                        "004","004","004","005"), 
                 year_mon = c(2021-01, 2021-02, 2021-03, 2021-01, 2021-01, 2021-05, 2021-06, 
                              2021-08, 2021-03, 2021-04, 2021-07, 2021-08),
                 value = c(15, 20, 25, 30, 19, 17, 18, 21, 39, 45, 21, 10))
id   year_mon  value  
001  2021-01      15  
001  2021-02      20    
001  2021-03      25  
002  2021-01      30  
003  2021-01      19  
003  2021-05      17  
003  2021-06      18  
003  2021-08      21  
004  2021-03      39  
004  2021-04      45  
004  2021-07      21  
005  2021-08      10  

我想每个 id 滞后 'value' 1 个月。但是,在 year_mon 列中缺少一些日期。

我试过:

new_df <- df %>%
  arrange(id, year_mon) %>% 
  group_by(id) %>% 
  mutate(lag_value = lag(value, 1L))

但这是返回上一行的值,而不是上个月的值。我该怎么做才能使数据输出为:

id   year_mon  value  lag_value  
001  2021-01      15  NA  
001  2021-02      20  15  
001  2021-03      25  20  
002  2021-01      30  NA  
003  2021-01      19  NA  
003  2021-05      17  NA  
003  2021-06      18  17  
003  2021-08      21  NA  
004  2021-03      39  NA  
004  2021-04      45  39  
004  2021-07      21  NA  
005  2021-08      10  NA  

如果 year_mon 中的月份不是 -1 月,则返回 NA

通过将它们转换为日期并使用 complete

临时填充所有缺失的月份
df %>%
  mutate(
    Date1 = as.Date(paste(year_mon,"-01",sep=""))
  ) %>%
  arrange(id, year_mon) %>% 
  group_by(id) %>%
  complete(Date1 = seq.Date(min(Date1), max(Date1), by='month')) %>%
  mutate(lag_value = lag(value, 1L)) %>%
  filter(!is.na(year_mon)) %>%
  select(-Date1)

   id    year_mon value lag_value
   <chr> <chr>    <dbl>     <dbl>
 1 001   2021-01     15        NA
 2 001   2021-02     20        15
 3 001   2021-03     25        20
 4 002   2021-01     30        NA
 5 003   2021-01     19        NA
 6 003   2021-05     17        NA
 7 003   2021-06     18        17
 8 003   2021-08     21        NA
 9 004   2021-03     39        NA
10 004   2021-04     45        39
11 004   2021-07     21        NA
12 005   2021-08     10        NA

定义一个函数diff_mon,其中returns 当前year_mon 和之前year_mon 之间的月份差异。它将参数转换为 yearmon class,然后使用 diff 获取当前条目和先前条目之间的年份差异。将其乘以 12 并四舍五入得到当前项目和上一个项目之间的月数。如果是 1,则使用滞后,否则使用 NA。

library(dplyr)
library(zoo)

# difference in months.
# x is character vec with format yyyy-mm (or has class with as.yearmon method)
diff_mon <- function(x) round(12 * c(NA, diff(as.yearmon(x))))

df %>% 
  arrange(id, year_mon) %>%
  group_by(id) %>%
  mutate(lag = ifelse(diff_mon(year_mon) == 1, lag(value), NA)) %>%
  ungroup

给予:

# A tibble: 12 x 4
   id    year_mon value   lag
   <chr> <chr>    <dbl> <dbl>
 1 001   2021-01     15    NA
 2 001   2021-02     20    15
 3 001   2021-03     25    20
 4 002   2021-01     30    NA
 5 003   2021-01     19    NA
 6 003   2021-05     17    NA
 7 003   2021-06     18    17
 8 003   2021-08     21    NA
 9 004   2021-03     39    NA
10 004   2021-04     45    39
11 004   2021-07     21    NA
12 005   2021-08     10    NA

备注

问题中 year_mon 值周围缺少引号,因此我们使用了这个。

df <- structure(list(id = c("001", "001", "001", "002", "003", "003", 
"003", "003", "004", "004", "004", "005"), year_mon = c("2021-01", 
"2021-02", "2021-03", "2021-01", "2021-01", "2021-05", "2021-06", 
"2021-08", "2021-03", "2021-04", "2021-07", "2021-08"), value = c(15, 
20, 25, 30, 19, 17, 18, 21, 39, 45, 21, 10)), class = "data.frame", row.names = c(NA, 
-12L))