1 시계열 데이터 역학관계

R에서 시계열 데이터를 처리하기 위한 전용 자료구조로 zoo, Z’s Ordered Observationsxts, eXtensible Time Series가 많이 활용되었지만, tidyverse 등장이후 시계열 자료구조도 lubridate 팩키지의 등장 이후 시계열이 아닌 많이 사용되는 데이터프레임에서 표준으로 자리를 잡아가고 있으며 tsibble이 두가지 큰 흐름의 간극을 매워가면서 새로운 지평을 열어가고 있다.

시계열 역학관계

2 tsibble 기본 1

tsibble(tbl_ts)은 티블(tibble) tidyverse의 시계열 자료구조를 확장한 것으로 제작되었고. ts, zoo, xts와 비교하여 볼 때 시간 인덱스를 본질적인 데이터 칼럼으로 둠으로써 이질적인 자료구조 처리를 내재적으로 가능하게 제작되었고 변수 하나 혹은 그 이상으로 구성된 “Key” 개념을 도입해서 시간 흐름에 따라 관측점 단위별로 식별이 가능하게 만들었다.

2.1 tsibble 객체 생성

tsibble() 함수로 tsibble 객체를 생성시킬 수 있을 뿐만 아니라 as_tsibble() 함수는 S3 메쏘드로 다른 객체를 tsibble 객체로 강제변환(coerce)시킨다. ts, mts 객체는 as_tsibble()함수로 tsibble 객체를 별도 다른 설정없이 강제변환이 가능한 반면, 티블 혹은 데이터프레임의 경우 인덱스(index)와 키(key) 변수를 식별하기 위해서 추가 작업이 다소 필요하다.

library(tidyverse)
library(tsibble)
library(lubridate)

weather <- nycflights13::weather %>% 
  select(origin, time_hour, temp, humid, precip)
weather
# A tibble: 26,115 x 5
   origin time_hour            temp humid precip
   <chr>  <dttm>              <dbl> <dbl>  <dbl>
 1 EWR    2013-01-01 01:00:00  39.0  59.4      0
 2 EWR    2013-01-01 02:00:00  39.0  61.6      0
 3 EWR    2013-01-01 03:00:00  39.0  64.4      0
 4 EWR    2013-01-01 04:00:00  39.9  62.2      0
 5 EWR    2013-01-01 05:00:00  39.0  64.4      0
 6 EWR    2013-01-01 06:00:00  37.9  67.2      0
 7 EWR    2013-01-01 07:00:00  39.0  64.4      0
 8 EWR    2013-01-01 08:00:00  39.9  62.2      0
 9 EWR    2013-01-01 09:00:00  39.9  62.2      0
10 EWR    2013-01-01 10:00:00  41    59.6      0
# ... with 26,105 more rows

nycflights13::weather 자료형은 티블로 시간변수는 time_hour가 되고, 3개 변수 temp, humid, precip은 관측변수가 되고, origin은 관측지점이 된다. tsibble 자료형을 설명하기 적합한 요소를 두루갖추고 있다. 티블/데이터프레임을 tsibble 객체로 변환시킬 경우 index= 인자로 시계열 정보를 담고 있는 변수를 지정하고 key= 인자를 통해 관측단위 변수를 지정시킨다. 이를 통해서 관측점(행)을 관측단위별 시계열 자료구조로 준비가 완료되었다. tsibble 객체가 생성되면서 내부적으로 키가 있는 경우 키를 기준값으로 정렬이 일차적으로 일어나고 인덱스를 기준으로 다시 한번 정렬된다. 키가 없는 경우 인덱스를 기준으로 정렬된다.

weather_tsbl <- as_tsibble(weather, index=time_hour, key=id(origin))
weather_tsbl
# A tsibble: 26,115 x 5 [1h] <America/New_York>
# Key:       origin [3]
   origin time_hour            temp humid precip
   <chr>  <dttm>              <dbl> <dbl>  <dbl>
 1 EWR    2013-01-01 01:00:00  39.0  59.4      0
 2 EWR    2013-01-01 02:00:00  39.0  61.6      0
 3 EWR    2013-01-01 03:00:00  39.0  64.4      0
 4 EWR    2013-01-01 04:00:00  39.9  62.2      0
 5 EWR    2013-01-01 05:00:00  39.0  64.4      0
 6 EWR    2013-01-01 06:00:00  37.9  67.2      0
 7 EWR    2013-01-01 07:00:00  39.0  64.4      0
 8 EWR    2013-01-01 08:00:00  39.9  62.2      0
 9 EWR    2013-01-01 09:00:00  39.9  62.2      0
10 EWR    2013-01-01 10:00:00  41    59.6      0
# ... with 26,105 more rows

tsibble 객체는 자동으로 시계열 기간에 대한 정보를 인식하여 반영시킨다.

  • integer/numeric: 단위(unit) 혹은 연도(Y)
  • yearquarter/yearqtr: 분기(Q)
  • yearmonth/yearmon: 월(M)
  • yearweek: 주(W)
  • Date: 일(D)
  • POSIXct: 시간(h), 분(m), 초(s), 천분의 1초(us), 백만분의 1초(ms)

Date 혹은 POSITct는 월단위를 지원하지 않지만 tsibbleyearmonth/yearmth를 지원한다. weather_tsbl 객체는 시계열 단위 [1h]와 함께 키도 origin [3]으로 명시적으로 나타내고 있다.

3 tsibble 객체 데이터 조작

데이터프레임 dplyr 동사 group_by()에 대응되는 tsibble index_by() 함수를 사용해서 lubridate 팩키지 함수를 사용해서 시간단위 인덱스 time_hour 변수를 as_date() 함수로 날짜형으로 변환시키고 나서 month() 함수를 사용해서 월단위로 시계열 단위를 변환시킨 후에 최고/최저 온도를 요약하여 정리한다.

weather_tsbl %>%
  group_by(origin) %>%
  index_by(month = yearmonth(time_hour)) %>% 
  summarise(
    temp_high = max(temp, na.rm = TRUE),
    temp_average = mean(temp, na.rm = TRUE),
    temp_low = min(temp, na.rm = TRUE)
  ) %>% 
  DT::datatable()

4 불규칙 시계열 데이터

데이터프레임을 tsibble 객체로 변환시킬 경우 기본디폴트 설정으로 regular=TRUE로 되어있다. 하지만, nycflights13::flights 데이터프레임의 경우 carrier, flight를 키로 두고 as_tsibble() 함수를 적용시킬 경우 불규칙 시간 간격을 갖는 시계열 데이터가 생성된다.

먼저 lubridate 팩키지 make_datetime() 함수를 가지고 시계열 날짜시간 sched_dep_datetime 변수를 생성시킨다.

flights <- nycflights13::flights %>%
  mutate(sched_dep_datetime = make_datetime(year, month, day, hour, minute, tz = "America/New_York")) %>% 
  select(carrier, flight, year, month, day, hour, minute, sched_dep_datetime, dep_delay)
flights
# A tibble: 336,776 x 9
   carrier flight  year month   day  hour minute sched_dep_datetime 
   <chr>    <int> <int> <int> <int> <dbl>  <dbl> <dttm>             
 1 UA        1545  2013     1     1     5     15 2013-01-01 05:15:00
 2 UA        1714  2013     1     1     5     29 2013-01-01 05:29:00
 3 AA        1141  2013     1     1     5     40 2013-01-01 05:40:00
 4 B6         725  2013     1     1     5     45 2013-01-01 05:45:00
 5 DL         461  2013     1     1     6      0 2013-01-01 06:00:00
 6 UA        1696  2013     1     1     5     58 2013-01-01 05:58:00
 7 B6         507  2013     1     1     6      0 2013-01-01 06:00:00
 8 EV        5708  2013     1     1     6      0 2013-01-01 06:00:00
 9 B6          79  2013     1     1     6      0 2013-01-01 06:00:00
10 AA         301  2013     1     1     6      0 2013-01-01 06:00:00
# ... with 336,766 more rows, and 1 more variable: dep_delay <dbl>

carrier, flight 변수를 key=을 설정하여 관측단위로 지정하고 make_datetime() 함수로 생성시킨 sched_dep_datetime 변수를 index=에 지정하고 regular = FALSE으로 불규칙 시계열 자료임을 명시적으로 선엉하여 tsibble 객체를 만든다.

flights_tsbl <- as_tsibble(flights, key=id(carrier, flight), 
                                    index=sched_dep_datetime, 
                                    regular = FALSE)
flights_tsbl
# A tsibble: 336,776 x 9 [!] <America/New_York>
# Key:       carrier, flight [5,725]
   carrier flight  year month   day  hour minute sched_dep_datetime 
   <chr>    <int> <int> <int> <int> <dbl>  <dbl> <dttm>             
 1 9E        2900  2013    11     3    15     40 2013-11-03 15:40:00
 2 9E        2900  2013    11     4    15     40 2013-11-04 15:40:00
 3 9E        2900  2013    11     5    15     40 2013-11-05 15:40:00
 4 9E        2900  2013    11     6    15     40 2013-11-06 15:40:00
 5 9E        2900  2013    11     7    15     40 2013-11-07 15:40:00
 6 9E        2900  2013    11     8    15     40 2013-11-08 15:40:00
 7 9E        2900  2013    11     9    15     40 2013-11-09 15:40:00
 8 9E        2900  2013    11    10    15     40 2013-11-10 15:40:00
 9 9E        2900  2013    11    11    15     40 2013-11-11 15:40:00
10 9E        2900  2013    11    12    15     40 2013-11-12 15:40:00
# ... with 336,766 more rows, and 1 more variable: dep_delay <dbl>

flights_tsbl 객체는 A tsibble: 336,776 x 9 [!] <America/New_York>에서 나타나듯이 [!] 표식을 통해 불규칙 시계열데이터임을 확인할 수 있다. 불규칙 시계열 데이터를 균등간격을 갖는 시계열 데이터로 변환시킬 경우 index_by() + summarize()를 사용한다. A tsibble: 22,789 x 4 [1M]에 나타난 것처럼 월별 [1M]로 균등간격을 갖는 시계열로 변환이 되었다.

flights_tsbl %>% 
  group_by(carrier, flight) %>% 
  index_by(month = yearmonth(sched_dep_datetime)) %>% 
  summarise(delay_mean = mean(dep_delay, na.rm=TRUE)) %>% 
  arrange(desc(delay_mean))
# A tsibble: 22,789 x 4 [1M]
# Key:       carrier, flight [5,725]
# Groups:    carrier [16]
   carrier flight   month delay_mean
   <chr>    <int>   <mth>      <dbl>
 1 UA         372  2013 7       483 
 2 UA         488  2013 1       379 
 3 DL        1091 2013 12       378.
 4 EV        5017  2013 9       372 
 5 9E        3552  2013 3       354 
 6 EV        5537  2013 7       350 
 7 WN         521  2013 9       346 
 8 DL         390  2013 9       334 
 9 EV        4670  2013 6       322 
10 EV        3261 2013 12       321 
# ... with 22,779 more rows

5 결측값(NA) 처리 2

본격적인 시계열 데이터 분석을 위해서 결측값(NA)에 대한 면밀한 조사가 선행되어야 한다. 이를 위해서 tsibble 팩키지는 다음 함수를 제공하고 있다.

  • has_gaps()
  • scan_gaps()
  • count_gaps()
  • fill_gaps()

pedestrian 데이터셋은 tsibble 팩키지에 내장된 tsibble 객체로 IoT 센서데이터를 담고 있는데 결측값이 상당수 포함되어 있다. Sensor 변수가 관측점별 키 역할을 하고 있으며 총 4개 센서가 있다. has_gaps() 함수를 통해 센서 4개 모두 결측값이 존재됨이 확인되었다.

pedestrian
# A tsibble: 66,037 x 5 [1h] <Australia/Melbourne>
# Key:       Sensor [4]
   Sensor         Date_Time           Date        Time Count
   <chr>          <dttm>              <date>     <int> <int>
 1 Birrarung Marr 2015-01-01 00:00:00 2015-01-01     0  1630
 2 Birrarung Marr 2015-01-01 01:00:00 2015-01-01     1   826
 3 Birrarung Marr 2015-01-01 02:00:00 2015-01-01     2   567
 4 Birrarung Marr 2015-01-01 03:00:00 2015-01-01     3   264
 5 Birrarung Marr 2015-01-01 04:00:00 2015-01-01     4   139
 6 Birrarung Marr 2015-01-01 05:00:00 2015-01-01     5    77
 7 Birrarung Marr 2015-01-01 06:00:00 2015-01-01     6    44
 8 Birrarung Marr 2015-01-01 07:00:00 2015-01-01     7    56
 9 Birrarung Marr 2015-01-01 08:00:00 2015-01-01     8   113
10 Birrarung Marr 2015-01-01 09:00:00 2015-01-01     9   166
# ... with 66,027 more rows
has_gaps(pedestrian)
# A tibble: 4 x 2
  Sensor                        .gaps
  <chr>                         <lgl>
1 Birrarung Marr                TRUE 
2 Bourke Street Mall (North)    TRUE 
3 QV Market-Elizabeth St (West) TRUE 
4 Southern Cross Station        TRUE 

결측값이 확인되면 다음으로 관심있는 사항은 결측값이 각 센서별로 몇개나 있는지 계산해야 한다. count_gaps() 함수를 통해서 각센서별 기간별 결측값이 발생된 횟수를 파악할 수 있다.

pedestrian %>% 
  count_gaps(.fill=TRUE) %>% 
  arrange(desc(.n))
# A tibble: 18 x 4
   Sensor                     .from               .to                    .n
   <chr>                      <dttm>              <dttm>              <int>
 1 Birrarung Marr             2016-10-29 00:00:00 2016-11-28 23:00:00   744
 2 Birrarung Marr             2015-10-06 00:00:00 2015-10-31 23:00:00   624
 3 Birrarung Marr             2016-04-08 00:00:00 2016-05-03 23:00:00   624
 4 Birrarung Marr             2015-05-07 00:00:00 2015-05-31 23:00:00   600
 5 Birrarung Marr             2015-11-26 00:00:00 2015-12-04 23:00:00   216
 6 Birrarung Marr             2015-11-20 00:00:00 2015-11-24 23:00:00   120
 7 Birrarung Marr             2015-11-05 00:00:00 2015-11-06 23:00:00    48
 8 QV Market-Elizabeth St (W~ 2015-12-31 00:00:00 2015-12-31 23:00:00    24
 9 Southern Cross Station     2016-03-29 02:00:00 2016-03-29 03:00:00     2
10 Birrarung Marr             2015-04-05 02:00:00 2015-04-05 02:00:00     1
11 Birrarung Marr             2016-04-03 02:00:00 2016-04-03 02:00:00     1
12 Bourke Street Mall (North) 2015-04-05 02:00:00 2015-04-05 02:00:00     1
13 Bourke Street Mall (North) 2016-04-03 02:00:00 2016-04-03 02:00:00     1
14 QV Market-Elizabeth St (W~ 2015-04-05 02:00:00 2015-04-05 02:00:00     1
15 QV Market-Elizabeth St (W~ 2016-04-03 02:00:00 2016-04-03 02:00:00     1
16 Southern Cross Station     2015-04-05 02:00:00 2015-04-05 02:00:00     1
17 Southern Cross Station     2016-03-08 02:00:00 2016-03-08 02:00:00     1
18 Southern Cross Station     2016-04-03 02:00:00 2016-04-03 02:00:00     1

다음으로 결측값에 대한 상세한 내용을 파악하려면 scan_gaps() 함수를 통해 파악할 수 있다.

pedestrian %>% 
  filter(Sensor == "Bourke Street Mall (North)") %>% 
  scan_gaps()
# A tsibble: 2 x 2 [1h] <Australia/Melbourne>
# Key:       Sensor [1]
  Sensor                     Date_Time          
  <chr>                      <dttm>             
1 Bourke Street Mall (North) 2015-04-05 02:00:00
2 Bourke Street Mall (North) 2016-04-03 02:00:00

ggplot 팩키지를 통해서 결측값을 시각화하여 파악하는 것도 가능하다. 이를 통해서 센서가 정상적으로 동작하지 않는 기간이 언제였는지 쉽게 파악할 수 있다.

pedestrian %>% 
  count_gaps(.fill=TRUE) %>% 
  ggplot(aes(x = Sensor, colour = Sensor)) +
    geom_linerange(aes(ymin = .from, ymax = .to)) +
    geom_point(aes(y = .from)) +
    geom_point(aes(y = .to)) +
    coord_flip() +
    theme(legend.position = "top") +
    labs(x="")

센서별로 결측값이 발생한 시간을 파악하게 되면 다음 단계로 결측값을 채워넣는다. fill_gaps() 함수를 사용한다. 시간별로 빈칸을 NA로 채워넣거나 mean(Count) 평균값을 포함한 다른 값으로도 채워넣는 것이 가능하다.

na_g <- pedestrian %>% 
  fill_gaps(.full=TRUE) %>% 
  ggplot(aes(x=Date_Time, y=Count, color=Sensor)) +
    geom_line() +
    facet_wrap(~Sensor) +
    theme(legend.position = "none")

fill_g <- pedestrian %>% 
  fill_gaps(Count = mean(Count), .full=TRUE) %>% 
  ggplot(aes(x=Date_Time, y=Count, color=Sensor)) +
    geom_line() +
    facet_wrap(~Sensor) +
    theme(legend.position = "none")

cowplot::plot_grid(na_g, fill_g)

6 윈도우 함수 3

시계열 데이터는 엄격한 시간 순서를 따르기 때문에 이를 기반으로 연산작업을 수행할 수 있다. 대표적인 시계열 연산이 이동평균을 들 수 있다. 명사 tsibble 객체에 다음 세가지 유형의 시계열 동사를 이동 윈도우에 적용시킬 수 있다.

  • slide()/slide2()/pslide(): 겹치는 시계열 관측점을 갖는 슬라이딩 윈도우
  • tile()/tile2()/ptile(): 겹치지 않는 시계열 관측점을 갖는 타일 윈도우
  • stretch()/stretch2()/pstretch(): 초기 윈도우를 고정시키고 관측점을 추가

pedestrian 데이터는 호주 멜버른시 시간대별 보행자수를 담고 있는 시계열 데이터로 Sensor가 키역할을 담당하고 Date_Time가 시계열 인덱스를 나타내고 있다. 결측값이 포함되어 있기 때문에 fill_gaps로 시계열 결측을 처리한다.

pedestrian_tsbl <- pedestrian %>% 
  fill_gaps(.full = TRUE)
pedestrian_tsbl
# A tsibble: 70,176 x 5 [1h] <Australia/Melbourne>
# Key:       Sensor [4]
   Sensor         Date_Time           Date        Time Count
   <chr>          <dttm>              <date>     <int> <int>
 1 Birrarung Marr 2015-01-01 00:00:00 2015-01-01     0  1630
 2 Birrarung Marr 2015-01-01 01:00:00 2015-01-01     1   826
 3 Birrarung Marr 2015-01-01 02:00:00 2015-01-01     2   567
 4 Birrarung Marr 2015-01-01 03:00:00 2015-01-01     3   264
 5 Birrarung Marr 2015-01-01 04:00:00 2015-01-01     4   139
 6 Birrarung Marr 2015-01-01 05:00:00 2015-01-01     5    77
 7 Birrarung Marr 2015-01-01 06:00:00 2015-01-01     6    44
 8 Birrarung Marr 2015-01-01 07:00:00 2015-01-01     7    56
 9 Birrarung Marr 2015-01-01 08:00:00 2015-01-01     8   113
10 Birrarung Marr 2015-01-01 09:00:00 2015-01-01     9   166
# ... with 70,166 more rows

7 이동평균

slide_dbl() 함수를 마치 map_dbl()와 같이 사용해서 이동평균을 구할 수 있고, .align= 인자를 통해 이동평균 적용 인덱스도 지정시킬 수 있다.

pedestrian_tsbl %>% 
  group_by(Sensor) %>% 
  mutate(Daily_MA = slide_dbl(Count, mean, na.rm = TRUE, .size = 3, .align = "center"
  ))
# A tsibble: 70,176 x 6 [1h] <Australia/Melbourne>
# Key:       Sensor [4]
# Groups:    Sensor [4]
   Sensor         Date_Time           Date        Time Count Daily_MA
   <chr>          <dttm>              <date>     <int> <int>    <dbl>
 1 Birrarung Marr 2015-01-01 00:00:00 2015-01-01     0  1630     NA  
 2 Birrarung Marr 2015-01-01 01:00:00 2015-01-01     1   826   1008. 
 3 Birrarung Marr 2015-01-01 02:00:00 2015-01-01     2   567    552. 
 4 Birrarung Marr 2015-01-01 03:00:00 2015-01-01     3   264    323. 
 5 Birrarung Marr 2015-01-01 04:00:00 2015-01-01     4   139    160  
 6 Birrarung Marr 2015-01-01 05:00:00 2015-01-01     5    77     86.7
 7 Birrarung Marr 2015-01-01 06:00:00 2015-01-01     6    44     59  
 8 Birrarung Marr 2015-01-01 07:00:00 2015-01-01     7    56     71  
 9 Birrarung Marr 2015-01-01 08:00:00 2015-01-01     8   113    112. 
10 Birrarung Marr 2015-01-01 09:00:00 2015-01-01     9   166    176. 
# ... with 70,166 more rows

8 달력기간

일별/주별/월별로 연산작업을 수행하고자 하는 경우 tsibble 객체에 리스트칼럼 개념을 도입할 경우 탈력적으로 작업할 수 있다. 먼저 월별로 시계열 데이터를 묶는 경우를 살펴보자. nest() 함수를 사용해서 월별로 데이터를 묶어낸다.

pedestrian_mth_tsbl <- pedestrian_tsbl %>% 
  mutate(YrMth = yearmonth(Date_Time)) %>% 
  nest(-Sensor, -YrMth)
pedestrian_mth_tsbl
# A tibble: 96 x 3
   Sensor           YrMth data               
   <chr>            <mth> <list>             
 1 Birrarung Marr  2015 1 <tsibble [744 x 4]>
 2 Birrarung Marr  2015 2 <tsibble [672 x 4]>
 3 Birrarung Marr  2015 3 <tsibble [744 x 4]>
 4 Birrarung Marr  2015 4 <tsibble [721 x 4]>
 5 Birrarung Marr  2015 5 <tsibble [744 x 4]>
 6 Birrarung Marr  2015 6 <tsibble [720 x 4]>
 7 Birrarung Marr  2015 7 <tsibble [744 x 4]>
 8 Birrarung Marr  2015 8 <tsibble [744 x 4]>
 9 Birrarung Marr  2015 9 <tsibble [720 x 4]>
10 Birrarung Marr 2015 10 <tsibble [743 x 4]>
# ... with 86 more rows

다음으로 앞선 slide_dbl() 함수에 .size=1로 지정하게 되면 월별 연산작업을 수행할 수 있다. 하지만, 3개월/6개월/12개월 작업을 할 경우 월별 리스트칼럼 데이터를 결합시켜야 한다. 예를 들어 분기별로 통계량을 계산하고자 할 경우 .size=3으로 지정하고 .bind = TRUE으로 설정한 후 3개월 이동평균을 계산하는 작업을 수행한다.

pedestrian_mth_tsbl %>% 
  group_by(Sensor) %>% 
  mutate(Monthly_MA = slide_dbl(data, 
    ~ mean(.$Count, na.rm = TRUE), .size = 3, .align = "center", .bind = TRUE
  ))
# A tibble: 96 x 4
# Groups:   Sensor [4]
   Sensor           YrMth data                Monthly_MA
   <chr>            <mth> <list>                   <dbl>
 1 Birrarung Marr  2015 1 <tsibble [744 x 4]>        NA 
 2 Birrarung Marr  2015 2 <tsibble [672 x 4]>       634.
 3 Birrarung Marr  2015 3 <tsibble [744 x 4]>       546.
 4 Birrarung Marr  2015 4 <tsibble [721 x 4]>       554.
 5 Birrarung Marr  2015 5 <tsibble [744 x 4]>       397.
 6 Birrarung Marr  2015 6 <tsibble [720 x 4]>       429.
 7 Birrarung Marr  2015 7 <tsibble [744 x 4]>       390.
 8 Birrarung Marr  2015 8 <tsibble [744 x 4]>       398.
 9 Birrarung Marr  2015 9 <tsibble [720 x 4]>       392.
10 Birrarung Marr 2015 10 <tsibble [743 x 4]>       539.
# ... with 86 more rows

9 달력기간별 회귀분석

filter_index() 함수로 “2015-03”월까지 추출하고 센서(Sensor)별로 묶은 후에 앞서 정의한 fit_reg() 함수를 적용시켜 회귀분석을 수행한다.

fit_reg <- function(...) {
  data <- tibble(...)
  fit <- lm(Count ~ Time, data = data)
  list(fitted = fitted(fit), resid = residuals(fit))
}

pedestrian_reg_tsbl <- pedestrian %>%
  filter_index(~ "2015-03") %>%
  nest(-Sensor) %>%
  mutate(reg = purrr::map(data, ~ pslide_dfr(., fit_reg, .size = 24 * 7)))

pedestrian_reg_tsbl
# A tibble: 4 x 3
  Sensor                        data                  reg                  
  <chr>                         <list>                <list>               
1 Birrarung Marr                <tsibble [2,160 x 4]> <tibble [334,825 x 2~
2 Bourke Street Mall (North)    <tsibble [1,032 x 4]> <tibble [145,321 x 2~
3 QV Market-Elizabeth St (West) <tsibble [2,160 x 4]> <tibble [334,825 x 2~
4 Southern Cross Station        <tsibble [2,160 x 4]> <tibble [334,825 x 2~
pedestrian_reg_tsbl$reg[[1]]
# A tibble: 334,825 x 2
   fitted   resid
    <dbl>   <dbl>
 1    NA     NA  
 2   161.  1469. 
 3   170.   656. 
 4   179.   388. 
 5   189.    75.3
 6   198.   -59.1
 7   208.  -131. 
 8   217.  -173. 
 9   226.  -170. 
10   236.  -123. 
# ... with 334,815 more rows