class: inverse background-image: linear-gradient(to right, rgba(150, 150, 150, .1), rgba(150, 150, 150, .4)), url("resources/hourglass.jpg") background-size: cover <style type="text/css"> /* custom.css */ .left-code { color: #777; width: 40%; height: 92%; float: left; } .right-plot { width: 58%; float: right; padding-left: 1%; } </style> .title[fable] .sticker-float[] ## Probabilistic cross-temporal hierarchies .bottom[ ### Mitchell O'Hara-Wild (<svg style="height:0.8em;top:.04em;position:relative;fill:#1da1f2;" viewBox="0 0 512 512"><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg>[@mitchoharawild](https://twitter.com/mitchoharawild)) ### 27 October 2020 ### Slides @ [slides.mitchelloharawild.com/isf2020](https://slides.mitchelloharawild.com/isf2020) ] --- class: inverse background-image: linear-gradient(to right, rgba(150, 150, 150, .1), rgba(150, 150, 150, .4)), url("resources/timezone.jpg") background-size: cover .title[Hello!] -- <br><br><br><br><br><br><br><br><br> .float-right[Let's talk about time.] --- class: inverse background-image: linear-gradient(to right, rgba(50, 50, 50, .1), rgba(200, 200, 200, .4)), url("resources/sparks.jpg") background-size: cover # Presentation driven development A 'proof of concept' for what is to come. **Everything** is subject to change, suggestions encouraged. -- .sticker-float[] --- class: center ## What is fable? .sticker[] -- .animated.fadeIn[ .sticker[] .sticker[] .sticker[] ## [tidyverts.org](http://www.tidyverts.org) ] --- class: top .sticker-float[] # Tidy temporal data structure ### Domestic tourism in Australia ```r library(tsibble) tourism ``` ``` #> # A tsibble: 24,320 x 5 [1Q] #> # Key: Region, State, Purpose [304] #> Quarter Region State Purpose Trips #> <qtr> <chr> <chr> <chr> <dbl> #> 1 1998 Q1 Adelaide South Australia Business 135. #> 2 1998 Q2 Adelaide South Australia Business 110. #> 3 1998 Q3 Adelaide South Australia Business 166. #> 4 1998 Q4 Adelaide South Australia Business 127. #> 5 1999 Q1 Adelaide South Australia Business 137. #> 6 1999 Q2 Adelaide South Australia Business 200. #> 7 1999 Q3 Adelaide South Australia Business 169. #> 8 1999 Q4 Adelaide South Australia Business 134. #> 9 2000 Q1 Adelaide South Australia Business 154. #> 10 2000 Q2 Adelaide South Australia Business 169. #> # … with 24,310 more rows ``` --- class: top .sticker-float[] # A peak at the features ### Compute features relating to STL decompositions ```r library(feasts) tourism_features <- tourism %>% features(Trips, feature_set(tags = "stl")) ``` ``` #> # A tibble: 304 x 12 #> Region State Purpose trend_strength seasonal_streng… seasonal_peak_y… seasonal_trough… spikiness linearity curvature #> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> #> 1 Adela… Sout… Busine… 0.451 0.380 3 1 1.62e+2 -5.51 71.4 #> 2 Adela… Sout… Holiday 0.541 0.601 1 3 9.95e+0 48.9 78.2 #> 3 Adela… Sout… Other 0.743 0.189 2 1 2.28e+0 95.0 43.4 #> 4 Adela… Sout… Visiti… 0.433 0.446 1 3 6.01e+1 34.9 71.1 #> 5 Adela… Sout… Busine… 0.453 0.140 3 1 1.18e-1 0.944 -3.30 #> 6 Adela… Sout… Holiday 0.512 0.244 2 1 1.92e-1 10.4 23.8 #> 7 Adela… Sout… Other 0.584 0.374 2 2 5.02e-4 4.29 3.21 #> 8 Adela… Sout… Visiti… 0.481 0.228 0 3 7.56e+0 34.3 -0.587 #> 9 Alice… Nort… Busine… 0.526 0.224 0 1 1.79e-1 23.8 19.6 #> 10 Alice… Nort… Holiday 0.377 0.827 3 1 8.13e-1 -19.6 10.3 #> # … with 294 more rows, and 2 more variables: stl_e_acf1 <dbl>, stl_e_acf10 <dbl> ``` --- class: top .sticker-float[] # A peak at the features .full-width[ ```r library(ggplot2) tourism_features %>% ggplot(aes(x = trend_strength, y = seasonal_strength_year, colour = Purpose)) + geom_point() + stat_density_2d(aes(fill = Purpose, alpha = ..level..), bins = 5, geom = "polygon") + facet_wrap(vars(Purpose), nrow = 1) + coord_equal() + xlim(c(0,1)) + ylim(c(0,1)) ``` <img src="figure/tourism-features-plot-1.svg" style="display: block; margin: auto;" /> ] --- class: top .sticker-float[].sticker-float[] # Total holidays across Australia ### Starting from the top ```r library(dplyr) aus_holiday <- tourism %>% filter(Purpose == "Holiday") %>% summarise(Trips = sum(Trips)) aus_holiday %>% autoplot(Trips) ``` .flex-row[ ``` #> # A tsibble: 80 x 2 [1Q] #> Quarter Trips #> <qtr> <dbl> #> 1 1998 Q1 11806. #> 2 1998 Q2 9276. #> 3 1998 Q3 8642. #> 4 1998 Q4 9300. #> 5 1999 Q1 11172. #> 6 1999 Q2 9608. #> 7 1999 Q3 8914. #> 8 1999 Q4 9026. #> 9 2000 Q1 11071. #> 10 2000 Q2 9196. #> # … with 70 more rows ``` .full-width[ <img src="figure/tourism-total-plot-1.svg" style="display: block; margin: auto;" /> ] ] --- class: top .sticker-float[] # Forecasting with fable ### Look at the data <br> .left-code[ ```r *aus_holiday ``` ] .right-plot[ ``` #> # A tsibble: 80 x 2 [1Q] #> Quarter Trips #> <qtr> <dbl> #> 1 1998 Q1 11806. #> 2 1998 Q2 9276. #> 3 1998 Q3 8642. #> 4 1998 Q4 9300. #> 5 1999 Q1 11172. #> 6 1999 Q2 9608. #> 7 1999 Q3 8914. #> 8 1999 Q4 9026. #> 9 2000 Q1 11071. #> 10 2000 Q2 9196. #> # … with 70 more rows ``` ] --- class: top .sticker-float[] # Forecasting with fable ### Specify and estimate a model <br> .left-code[ ```r aus_holiday %>% * model(ETS(Trips)) ``` ] .right-plot[ ``` #> # A mable: 1 x 1 #> `ETS(Trips)` #> <model> #> 1 <ETS(M,N,M)> ``` ] --- class: top .sticker-float[] # Forecasting with fable ### Make some forecasts <br> .left-code[ ```r aus_holiday %>% model(ETS(Trips)) %>% * forecast(h = "3 years") ``` ] .right-plot[ ``` #> # A fable: 12 x 4 [1Q] #> # Key: .model [1] #> .model Quarter Trips .mean #> <chr> <qtr> <dist> <dbl> #> 1 ETS(Trips) 2018 Q1 N(13088, 368663) 13088. #> 2 ETS(Trips) 2018 Q2 N(10909, 288993) 10909. #> 3 ETS(Trips) 2018 Q3 N(10442, 294873) 10442. #> 4 ETS(Trips) 2018 Q4 N(10624, 336446) 10624. #> 5 ETS(Trips) 2019 Q1 N(13088, 558216) 13088. #> 6 ETS(Trips) 2019 Q2 N(10909, 420721) 10909. #> 7 ETS(Trips) 2019 Q3 N(10442, 415586) 10442. #> 8 ETS(Trips) 2019 Q4 N(10624, 461447) 10624. #> 9 ETS(Trips) 2020 Q1 N(13088, 747978) 13088. #> 10 ETS(Trips) 2020 Q2 N(10909, 552594) 10909. #> 11 ETS(Trips) 2020 Q3 N(10442, 536433) 10442. #> 12 ETS(Trips) 2020 Q4 N(10624, 586585) 10624. ``` ] --- class: top .sticker-float[] # Forecasting with fable ### See the results! <br> .left-code[ ```r aus_holiday %>% model(ETS(Trips)) %>% forecast(h = "3 years") %>% * autoplot(aus_holiday) ``` ] .right-plot[ <img src="figure/tourism-total-ets-plot-output-1.svg" style="display: block; margin: auto;" /> ] --- class: inverse, center background-image: linear-gradient(to right, rgba(50, 50, 50, .5), rgba(50, 50, 50, .5)), url("resources/hierarchy.jpg") background-size: cover # Forecasting hierarchical series -- `aggregate_key()` --- # Forecasting hierarchical series ```r data %>% aggregate_key(grp_a / grp_b, y = sum(y)) ```  --- # Consider tourism by state <img src="figure/ausmap-1.svg" style="display: block; margin: auto;" /> .footnote[*Map courtesy of Rob Hyndman*] --- # Consider tourism by state .pull-left[ ```r tourism_state <- tourism %>% * aggregate_key(State, Trips = sum(Trips)) ``` ``` #> # A tsibble: 720 x 3 [1Q] #> # Key: State [9] #> Quarter State Trips #> <qtr> <chr*> <dbl> #> 1 1998 Q1 <aggregated> 23182. #> 2 1998 Q2 <aggregated> 20323. #> 3 1998 Q3 <aggregated> 19827. #> 4 1998 Q4 <aggregated> 20830. #> 5 1999 Q1 <aggregated> 22087. #> 6 1999 Q2 <aggregated> 21458. #> 7 1999 Q3 <aggregated> 19914. #> 8 1999 Q4 <aggregated> 20028. #> 9 2000 Q1 <aggregated> 22339. #> 10 2000 Q2 <aggregated> 19941. #> # … with 710 more rows ``` ] .pull-right[ <img src="figure/tourism-agg-plot-1.svg" style="display: block; margin: auto;" /> ] --- # Forecasting each series separately .pull-left[ ```r fc <- tourism_state %>% model(ets = ETS(Trips)) %>% forecast(h = "3 years") ``` ``` #> # A fable: 108 x 5 [1Q] #> # Key: State, .model [9] #> State .model Quarter Trips .mean #> <chr*> <chr> <qtr> <dist> <dbl> #> 1 ACT ets 2018 Q1 N(701, 7651) 701. #> 2 ACT ets 2018 Q2 N(717, 8032) 717. #> 3 ACT ets 2018 Q3 N(734, 8440) 734. #> 4 ACT ets 2018 Q4 N(750, 8882) 750. #> 5 ACT ets 2019 Q1 N(767, 9368) 767. #> 6 ACT ets 2019 Q2 N(784, 9905) 784. #> 7 ACT ets 2019 Q3 N(800, 10503) 800. #> 8 ACT ets 2019 Q4 N(817, 11171) 817. #> 9 ACT ets 2020 Q1 N(833, 11919) 833. #> 10 ACT ets 2020 Q2 N(850, 12756) 850. #> # … with 98 more rows ``` ] .pull-right[ <img src="figure/tourism-agg-base-output-1.svg" style="display: block; margin: auto;" /> ] --- # Reconciling forecasts by state .pull-left[ ```r fc_coherent <- tourism_state %>% model(ets = ETS(Trips)) %>% * reconcile(mint_ets = min_trace(ets)) %>% forecast(h = "3 years") ``` ``` #> # A fable: 216 x 5 [1Q] #> # Key: State, .model [18] #> State .model Quarter Trips .mean #> <chr*> <chr> <qtr> <dist> <dbl> #> 1 ACT ets 2018 Q1 N(701, 7651) 701. #> 2 ACT ets 2018 Q2 N(717, 8032) 717. #> 3 ACT ets 2018 Q3 N(734, 8440) 734. #> 4 ACT ets 2018 Q4 N(750, 8882) 750. #> 5 ACT ets 2019 Q1 N(767, 9368) 767. #> 6 ACT ets 2019 Q2 N(784, 9905) 784. #> 7 ACT ets 2019 Q3 N(800, 10503) 800. #> 8 ACT ets 2019 Q4 N(817, 11171) 817. #> 9 ACT ets 2020 Q1 N(833, 11919) 833. #> 10 ACT ets 2020 Q2 N(850, 12756) 850. #> # … with 206 more rows ``` ] .pull-right[ <img src="figure/tourism-agg-coherent-output-1.svg" style="display: block; margin: auto;" /> ] --- class: inverse, center background-image: linear-gradient(to right, rgba(50, 50, 50, .5), rgba(50, 50, 50, .5)), url("resources/many_clocks.jpg") background-size: cover # Forecasting temporal granularities -- `aggregate_index()` --- # Forecasting temporal granularities .float-right[] ```r library(moment) # pkg.mitchelloharawild.com/moment/ data %>% aggregate_index(c(tu_year(1), tu_quarter(2), tu_quarter(1), tu_month(1)), y = sum(y)) ```  --- # Temporal aggregations of Australian holidays ```r library(moment) aus_holiday_temporal <- aus_holiday %>% * aggregate_index(c(tu_year(1), tu_quarter(2), tu_quarter(1)), Trips = sum(Trips)) ``` .pull-left[ ``` #> # A tsibble: 140 x 2 [1Y, 2Q, 1Q] #> Quarter Trips #> <moment> <dbl> #> 1 1998 39024. #> 2 1999 38719. #> 3 2000 38599. #> 4 2001 37990. #> 5 2002 38159. #> 6 2003 37277. #> 7 2004 37216. #> 8 2005 34833. #> 9 2006 37218. #> 10 2007 37601. #> # … with 130 more rows ``` ] .pull-right[ <img src="figure/tourism-time-agg-plot-1.svg" style="display: block; margin: auto;" /> ] --- # Forecasting each series separately .pull-left[ ```r fc <- aus_holiday_temporal %>% model(ets = ETS(Trips)) %>% forecast(h = "3 years") ``` ``` #> # A fable: 21 x 4 [1Y, 2Q, 1Q] #> # Key: .model [1] #> .model Quarter Trips .mean #> <chr> <moment> <dist> <dbl> #> 1 ets 2018 N(44587, 1768165) 44587. #> 2 ets 2019 N(44587, 3535974) 44587. #> 3 ets 2020 N(44587, 5303783) 44587. #> 4 ets 2018 Q3-Q4 N(24133, 490947) 24133. #> 5 ets 2019 Q3-Q4 N(22168, 614810) 22168. #> 6 ets 2020 Q3-Q4 N(25076, 8e+05) 25076. #> 7 ets 2021 Q3-Q4 N(23110, 1060950) 23110. #> 8 ets 2022 Q3-Q4 N(26019, 1408284) 26019. #> 9 ets 2023 Q3-Q4 N(24053, 1855035) 24053. #> 10 ets 2018 Q1 N(13088, 368663) 13088. #> # … with 11 more rows ``` ] .pull-right[ <img src="figure/tourism-time-agg-base-output-1.svg" style="display: block; margin: auto;" /> ] --- # Reconciling forecasts over time .pull-left[ ```r fc <- aus_holiday_temporal %>% model(ets = ETS(Trips)) %>% * reconcile(mint_ets = min_trace(ets)) %>% forecast(h = "3 years") ``` ``` #> # A fable: 42 x 4 [1Y, 2Q, 1Q] #> # Key: .model [2] #> .model Quarter Trips .mean #> <chr> <moment> <dist> <dbl> #> 1 ets 2018 N(44587, 1768165) 44587. #> 2 ets 2019 N(44587, 3535974) 44587. #> 3 ets 2020 N(44587, 5303783) 44587. #> 4 mint_ets 2018 N(45454, 461746) 45454. #> 5 mint_ets 2019 N(46170, 743625) 46170. #> 6 mint_ets 2020 N(46885, 1119338) 46885. #> 7 ets 2018 Q3-Q4 N(24133, 490947) 24133. #> 8 ets 2019 Q3-Q4 N(22168, 614810) 22168. #> 9 ets 2020 Q3-Q4 N(25076, 8e+05) 25076. #> 10 ets 2021 Q3-Q4 N(23110, 1060950) 23110. #> # … with 32 more rows ``` ] .pull-right[ <img src="figure/tourism-time-agg-coherent-output-1.svg" style="display: block; margin: auto;" /> ] --- class: inverse, center background-image: linear-gradient(to bottom, rgba(50, 50, 50, .8), rgba(50, 50, 50, .5)), url("resources/clock_stack.jpg") background-size: cover # Cross-temporal forecast reconciliation -- `aggregate_key() %>% aggregate_index()` --- # Cross-temporal forecast reconciliation ```r data %>% aggregate_key(grp_a / grp_b, y = sum(y)) %>% aggregate_index(c(tu_year(1), tu_quarter(2), tu_quarter(1), tu_month(1)), y = sum(y)) ``` .pull-left[  ] .pull-right[  ] --- # Purpose of travel at multiple granularities ```r library(moment) tourism_purpose_temporal <- tourism %>% * aggregate_key(Purpose, Trips = sum(Trips)) %>% * aggregate_index(c(tu_year(1), tu_quarter(1)), Trips = sum(Trips)) ``` .pull-left[ ``` #> # A tsibble: 500 x 3 [1Y, 1Q] #> # Key: Purpose [5] #> Quarter Purpose Trips #> <moment> <chr*> <dbl> #> 1 1998 Business 15474. #> 2 1998 Holiday 39024. #> 3 1998 Other 2820. #> 4 1998 Visiting 26844. #> 5 1998 <aggregated> 84162. #> 6 1999 Business 15940. #> 7 1999 Holiday 38719. #> 8 1999 Other 3320. #> 9 1999 Visiting 25508. #> 10 1999 <aggregated> 83488. #> # … with 490 more rows ``` ] .pull-right[ <img src="figure/tourism-crosstemp-agg-plot-1.svg" style="display: block; margin: auto;" /> ] --- # Forecasting each series separately .pull-left[ ```r fc <- tourism_purpose_temporal %>% model(ets = ETS(Trips)) %>% forecast(h = "3 years") ``` ``` #> # A fable: 75 x 5 [1Y, 1Q] #> # Key: Purpose, .model [5] #> Purpose .model Quarter Trips .mean #> <chr*> <chr> <moment> <dist> <dbl> #> 1 Business ets 2018 N(22296, 3e+06) 22296. #> 2 Business ets 2019 N(22296, 6e+06) 22296. #> 3 Business ets 2020 N(22296, 9078586) 22296. #> 4 Business ets 2018 Q1 N(4937, 137658) 4937. #> 5 Business ets 2018 Q2 N(5604, 209086) 5604. #> 6 Business ets 2018 Q3 N(5888, 268396) 5888. #> 7 Business ets 2018 Q4 N(5575, 293305) 5575. #> 8 Business ets 2019 Q1 N(4937, 3e+05) 4937. #> 9 Business ets 2019 Q2 N(5604, 367634) 5604. #> 10 Business ets 2019 Q3 N(5888, 427147) 5888. #> # … with 65 more rows ``` ] .pull-right[ <img src="figure/tourism-crosstemp-agg-base-output-1.svg" style="display: block; margin: auto;" /> ] --- # Reconciling forecasts over time .pull-left[ ```r fc <- tourism_purpose_temporal %>% model(ets = ETS(Trips)) %>% * reconcile(mint_ets = min_trace(ets)) %>% forecast(h = "3 years") ``` ``` #> # A fable: 150 x 5 [1Y, 1Q] #> # Key: Purpose, .model [10] #> Purpose .model Quarter Trips .mean #> <chr*> <chr> <moment> <dist> <dbl> #> 1 Business ets 2018 N(22296, 3e+06) 22296. #> 2 Business ets 2019 N(22296, 6e+06) 22296. #> 3 Business ets 2020 N(22296, 9078586) 22296. #> 4 Business mint_ets 2018 N(22431, 629048) 22431. #> 5 Business mint_ets 2019 N(22803, 1115028) 22803. #> 6 Business mint_ets 2020 N(23174, 1621665) 23174. #> 7 Business ets 2018 Q1 N(4937, 137658) 4937. #> 8 Business ets 2018 Q2 N(5604, 209086) 5604. #> 9 Business ets 2018 Q3 N(5888, 268396) 5888. #> 10 Business ets 2018 Q4 N(5575, 293305) 5575. #> # … with 140 more rows ``` ] .pull-right[ <img src="figure/tourism-crosstemp-agg-coherent-output-1.svg" style="display: block; margin: auto;" /> ] --- class: inverse, top background-image: linear-gradient(to right, rgba(50, 50, 50, .5), rgba(150, 150, 150, .4)), url("resources/hourglass.jpg") background-size: cover .sticker-float[] .title[Summary <svg style="height:0.8em;top:.04em;position:relative;fill:white;" viewBox="0 0 512 512"><path d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"/></svg>] ```r *library(tsibble) library(moment) library(fable) *tourism %>% aggregate_key(Purpose, Trips = sum(Trips)) %>% aggregate_index(c(tu_year(1), tu_quarter(1)), Trips = sum(Trips)) %>% model(ets = ETS(Trips)) %>% reconcile(mint_ets = min_trace(ets)) %>% forecast(h = "3 years") ``` Tidy temporal data suitable for the future of time series --- class: inverse, top background-image: linear-gradient(to right, rgba(50, 50, 50, .5), rgba(150, 150, 150, .4)), url("resources/hourglass.jpg") background-size: cover .sticker-float[] .title[Summary <svg style="height:0.8em;top:.04em;position:relative;fill:white;" viewBox="0 0 512 512"><path d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"/></svg>] ```r library(tsibble) *library(moment) library(fable) tourism %>% * aggregate_key(Purpose, Trips = sum(Trips)) %>% * aggregate_index(c(tu_year(1), tu_quarter(1)), Trips = sum(Trips)) %>% model(ets = ETS(Trips)) %>% reconcile(mint_ets = min_trace(ets)) %>% forecast(h = "3 years") ``` Produce aggregations of the data you want to forecast --- class: inverse, top background-image: linear-gradient(to right, rgba(50, 50, 50, .5), rgba(150, 150, 150, .4)), url("resources/hourglass.jpg") background-size: cover .sticker-float[] .title[Summary <svg style="height:0.8em;top:.04em;position:relative;fill:white;" viewBox="0 0 512 512"><path d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"/></svg>] ```r library(tsibble) library(moment) *library(fable) tourism %>% aggregate_key(Purpose, Trips = sum(Trips)) %>% aggregate_index(c(tu_year(1), tu_quarter(1)), Trips = sum(Trips)) %>% * model(ets = ETS(Trips)) %>% reconcile(mint_ets = min_trace(ets)) %>% forecast(h = "3 years") ``` Use any model to fit the data* .bottom.footnote[*for coherent probabilistic forecasts, the model must forecasts with a Normal distribution] --- class: inverse, top background-image: linear-gradient(to right, rgba(50, 50, 50, .5), rgba(150, 150, 150, .4)), url("resources/hourglass.jpg") background-size: cover .sticker-float[] .title[Summary <svg style="height:0.8em;top:.04em;position:relative;fill:white;" viewBox="0 0 512 512"><path d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"/></svg>] ```r library(tsibble) library(moment) library(fable) tourism %>% aggregate_key(Purpose, Trips = sum(Trips)) %>% aggregate_index(c(tu_year(1), tu_quarter(1)), Trips = sum(Trips)) %>% model(ets = ETS(Trips)) %>% * reconcile(mint_ets = min_trace(ets)) %>% forecast(h = "3 years") ``` Specify the reconciliation method to be used. --- class: inverse, top background-image: linear-gradient(to right, rgba(50, 50, 50, .5), rgba(150, 150, 150, .4)), url("resources/hourglass.jpg") background-size: cover .sticker-float[] .title[Summary <svg style="height:0.8em;top:.04em;position:relative;fill:white;" viewBox="0 0 512 512"><path d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"/></svg>] ```r library(tsibble) library(moment) library(fable) tourism %>% aggregate_key(Purpose, Trips = sum(Trips)) %>% aggregate_index(c(tu_year(1), tu_quarter(1)), Trips = sum(Trips)) %>% model(ets = ETS(Trips)) %>% reconcile(mint_ets = min_trace(ets)) %>% * forecast(h = "3 years") ``` Produce cross-temporally reconciled forecasts! --- class: inverse, top background-image: linear-gradient(to right, rgba(150, 150, 150, .1), rgba(150, 150, 150, .4)), url("resources/hourglass.jpg") background-size: cover .sticker-float[] .title[Thanks! <svg style="height:0.8em;top:.04em;position:relative;fill:white;" viewBox="0 0 576 512"><path d="M416 192c0-88.4-93.1-160-208-160S0 103.6 0 192c0 34.3 14.1 65.9 38 92-13.4 30.2-35.5 54.2-35.8 54.5-2.2 2.3-2.8 5.7-1.5 8.7S4.8 352 8 352c36.6 0 66.9-12.3 88.7-25 32.2 15.7 70.3 25 111.3 25 114.9 0 208-71.6 208-160zm122 220c23.9-26 38-57.7 38-92 0-66.9-53.5-124.2-129.3-148.1.9 6.6 1.3 13.3 1.3 20.1 0 105.9-107.7 192-240 192-10.8 0-21.3-.8-31.7-1.9C207.8 439.6 281.8 480 368 480c41 0 79.1-9.2 111.3-25 21.8 12.7 52.1 25 88.7 25 3.2 0 6.1-1.9 7.3-4.8 1.3-2.9.7-6.3-1.5-8.7-.3-.3-22.4-24.2-35.8-54.5z"/></svg>] .larger[ <svg style="height:0.8em;top:.04em;position:relative;fill:white;" viewBox="0 0 496 512"><path d="M336.5 160C322 70.7 287.8 8 248 8s-74 62.7-88.5 152h177zM152 256c0 22.2 1.2 43.5 3.3 64h185.3c2.1-20.5 3.3-41.8 3.3-64s-1.2-43.5-3.3-64H155.3c-2.1 20.5-3.3 41.8-3.3 64zm324.7-96c-28.6-67.9-86.5-120.4-158-141.6 24.4 33.8 41.2 84.7 50 141.6h108zM177.2 18.4C105.8 39.6 47.8 92.1 19.3 160h108c8.7-56.9 25.5-107.8 49.9-141.6zM487.4 192H372.7c2.1 21 3.3 42.5 3.3 64s-1.2 43-3.3 64h114.6c5.5-20.5 8.6-41.8 8.6-64s-3.1-43.5-8.5-64zM120 256c0-21.5 1.2-43 3.3-64H8.6C3.2 212.5 0 233.8 0 256s3.2 43.5 8.6 64h114.6c-2-21-3.2-42.5-3.2-64zm39.5 96c14.5 89.3 48.7 152 88.5 152s74-62.7 88.5-152h-177zm159.3 141.6c71.4-21.2 129.4-73.7 158-141.6h-108c-8.8 56.9-25.6 107.8-50 141.6zM19.3 352c28.6 67.9 86.5 120.4 158 141.6-24.4-33.8-41.2-84.7-50-141.6h-108z"/></svg> Learn more: [fable.tidyverts.org](https://fable.tidyverts.org/) <svg style="height:0.8em;top:.04em;position:relative;fill:white;" viewBox="0 0 512 512"><path d="M496 384H64V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-32c0-8.84-7.16-16-16-16zM464 96H345.94c-21.38 0-32.09 25.85-16.97 40.97l32.4 32.4L288 242.75l-73.37-73.37c-12.5-12.5-32.76-12.5-45.25 0l-68.69 68.69c-6.25 6.25-6.25 16.38 0 22.63l22.62 22.62c6.25 6.25 16.38 6.25 22.63 0L192 237.25l73.37 73.37c12.5 12.5 32.76 12.5 45.25 0l96-96 32.4 32.4c15.12 15.12 40.97 4.41 40.97-16.97V112c.01-8.84-7.15-16-15.99-16z"/></svg> Keep updated: [tidyverts.org](http://www.tidyverts.org) <svg style="height:0.8em;top:.04em;position:relative;fill:white;" viewBox="0 0 576 512"><path d="M528 0H48C21.5 0 0 21.5 0 48v320c0 26.5 21.5 48 48 48h192l-16 48h-72c-13.3 0-24 10.7-24 24s10.7 24 24 24h272c13.3 0 24-10.7 24-24s-10.7-24-24-24h-72l-16-48h192c26.5 0 48-21.5 48-48V48c0-26.5-21.5-48-48-48zm-16 352H64V64h448v288z"/></svg> Review slides: [slides.mitchelloharawild.com/isf2020](https://slides.mitchelloharawild.com/isf2020) <svg style="height:0.8em;top:.04em;position:relative;fill:white;" viewBox="0 0 512 512"><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg> Say hello: [@mitchoharawild](twitter.com/mitchoharawild/) <br> .bottom[This work is licensed as <svg style="height:0.8em;top:.04em;position:relative;fill:white;" viewBox="0 0 496 512"><path d="M245.83 214.87l-33.22 17.28c-9.43-19.58-25.24-19.93-27.46-19.93-22.13 0-33.22 14.61-33.22 43.84 0 23.57 9.21 43.84 33.22 43.84 14.47 0 24.65-7.09 30.57-21.26l30.55 15.5c-6.17 11.51-25.69 38.98-65.1 38.98-22.6 0-73.96-10.32-73.96-77.05 0-58.69 43-77.06 72.63-77.06 30.72-.01 52.7 11.95 65.99 35.86zm143.05 0l-32.78 17.28c-9.5-19.77-25.72-19.93-27.9-19.93-22.14 0-33.22 14.61-33.22 43.84 0 23.55 9.23 43.84 33.22 43.84 14.45 0 24.65-7.09 30.54-21.26l31 15.5c-2.1 3.75-21.39 38.98-65.09 38.98-22.69 0-73.96-9.87-73.96-77.05 0-58.67 42.97-77.06 72.63-77.06 30.71-.01 52.58 11.95 65.56 35.86zM247.56 8.05C104.74 8.05 0 123.11 0 256.05c0 138.49 113.6 248 247.56 248 129.93 0 248.44-100.87 248.44-248 0-137.87-106.62-248-248.44-248zm.87 450.81c-112.54 0-203.7-93.04-203.7-202.81 0-105.42 85.43-203.27 203.72-203.27 112.53 0 202.82 89.46 202.82 203.26-.01 121.69-99.68 202.82-202.84 202.82z"/></svg> BY-NC 4.0.] ]