rtimemergetime-seriestibble

merging irregular time ser


I want to merge multiple (>2) time series into a single object. For example, here are multiple time series (w missing data, incomplete, and irregular):

library(tidyverse)
library(zoo)

A <- tibble(
  date = seq(ymd("1927-10-01"), ymd("1927-10-07"), by = "days"),
  flow = sample.int(100, 7))
B <- tibble(
  date = seq(ymd("1927-10-01"), ymd("1927-10-07"), by = "days"),
  flow = c(48, 71, NA, 8, 92, 22, 49))
C <- tibble(
  date = seq(ymd("1927-10-03"), ymd("1927-10-05"), by = "days"),
  flow = sample.int(100, 3))
D <- tibble(
  date = ymd("1927-10-02", "1927-10-03", "1927-10-05", "1927-10-06", "1927-10-07"),
  flow = sample.int(100, 5))

I tried the following...

merge.zoo(A, B, C, D)

A and B are fine, but C is misaligned and D fails to address the missing data for 1927-10-04.

I'd like to get a data frame or tibble with a single column for 'date' (sequential, no missing dates) and four columns with the flow data labeled 'A', 'B', etc.

Thinking that the issue may be with the format of the time series I'm trying to merge, I tried creating my example time series using tsibble(), but got the comparable results, I also tried using zoo(), but get an error:

A <- zoo(
  date = seq(ymd("1927-10-01"), ymd("1927-10-07"), by = "days"),
  flow = sample.int(100, 7))

I've tried many different approaches (cbind, merge, full_join, bind_cols, ts.union, ts.intersect)--I expect many of these, possibly all, might work but didn't for me. What am I missing?

Thanks!


Solution

  • 1) merge.zoo merge.zoo is used with zoo objects so convert the input to zoo, perform the merge and convert back. Omit the last line if you want a zoo object rather than a data frame result.

    library(tibble)
    library(lubridate)
    library(zoo)
    
    L <- lst(A, B, C, D)
    
    L %>% 
      lapply(read.zoo) %>% # create list of zoo objects
      do.call(what = "merge") %>% 
      fortify.zoo(name = "date") # convert zoo to data frame
    
    ##         date  A  B  C  D
    ## 1 1927-10-01 34 48 NA NA
    ## 2 1927-10-02 18 71 NA 35
    ## 3 1927-10-03 63 NA 38  8
    ## 4 1927-10-04 70  8 72 NA
    ## 5 1927-10-05 16 92 29 46
    ## 6 1927-10-06 68 22 NA 40
    ## 7 1927-10-07 88 49 NA 45
    

    2) Base R Create the same list L and then rename the second column to A, B, C and D of the components respectively and finally use Reduce to repeatedly invoke the merges.

    L <- mget(c("A", "B", "C", "D"))
    
    lapply(names(L), \(nm) setNames(L[[nm]], c("date", nm))) |>
      Reduce(f = \(...) merge(..., all = TRUE))