ETS-prognoser i R
Apr 13, 2020
Filip Wästberg
6 minute read

Prognoser är ett viktigt verktyg för vilken verksamhet som helst. Det underlättar resursplanering och väl utfört ger det en indikation om vart en verksamhet är på väg.

En av de klassiska arbetshästarna inom tidsserieanalys är ETS(Exponential Smoothing). Modellen är populär då den ofta ger bra prognoser och är enkel att förstå.

Modellen skapar en prognos genom att räkna ut ett viktat medelvärde, där äldre observationer får en exponentiellt mindre vikt, medan senare observationer får en högre vikt. Vill du lära dig mer om ETS finns det väl dokumenterat här.

Med tanke på ETS popularitet, samt att den inte är så beräkningstung, är det inte konstigt att det är den modellen som Excel byggt in i sin funktion för prognoser. Är du nyfiken på hur du gör det i Excel kan du kolla det här inlägget av David Stavegård som gör omtyckta #torsdagstips i Excel på LinkedIn.

Men jag tänkte att vi skulle gå igenom hur man gör en ETS-prognos i R och hur man kan jämföra den mot andra prognosmodeller. Vi utgår från samma data som David använder, som är exempeldata från Excels hemsida. Det kan vi enkelt ladda ner med download.file().

download.file("https://download.microsoft.com/download/7/8/E/78E7FB59-A554-4586-B3F4-AEAEBC4036AF/Forecast_ets_example.xlsx", 
                                                        destfile = "Forecast_ets_example.xlsx")

För att läsa in Excel-filen använder vi paketet readxl och tidyverse. Vi hoppar över de två första raderna i arbetsboken som är tomma och läser bara in de fem första kolumnerna. Vi använder också paketet janitor och funktionen clean_names() för att få lite bättre ordning på kolumnnamnen.

library(tidyverse)
library(readxl)
library(janitor)

ets_ex <- read_excel("Forecast_ets_example.xlsx", skip = 2) %>% 
    select(1:5) %>% 
    clean_names()

Inspekterar vi arbetsbladet så ser vi att det handlar om antalet passagerare på en flygplats och att det är kolumnen airport_passengers som vi ska bygga en prognos på. De andra kolumnerna innehåller värden för den prognos som gjorts i Excel.

ets_ex
## # A tibble: 81 x 5
##    date                airport_passeng… forecast_airpor… lower_confidenc…
##    <dttm>                         <dbl>            <dbl>            <dbl>
##  1 2009-01-01 00:00:00          2644539               NA               NA
##  2 2009-02-01 00:00:00          2359800               NA               NA
##  3 2009-03-01 00:00:00          2925918               NA               NA
##  4 2009-04-01 00:00:00          3024973               NA               NA
##  5 2009-05-01 00:00:00          3177100               NA               NA
##  6 2009-06-01 00:00:00          3419595               NA               NA
##  7 2009-07-01 00:00:00          3649702               NA               NA
##  8 2009-08-01 00:00:00          3650668               NA               NA
##  9 2009-09-01 00:00:00          3191526               NA               NA
## 10 2009-10-01 00:00:00          3249428               NA               NA
## # … with 71 more rows, and 1 more variable:
## #   upper_confidence_bound_airport_passengers <dbl>

Prognosticering i R

För att jobba med tidsserier och prognosticering i R brukar jag använda mig av tre paket:

  • fable för att anpassa modeller och göra prognoser
  • tsibble för att jobba med tidsserier, exempelvis identifiera gap i tidsserien
  • feasts för feature extraction, d.v.s. undersöka säsongsvariation och trend.
library(fable)
library(tsibble)
library(feasts)

Definiera tidsserien

  • Eftersom vi endast är intresserade av ursprungskolumnen airport_passenger tar vi bort de andra kolumnerna.
  • Vi filtrerar också bort alla saknade värden.
  • Vi definierar date som yearmonth()
  • Till sist definierar vi det här som en tidsserie med as_tsibble(). Vi ser då också att den väljer date som indexvariabel.
airport_ts <- ets_ex %>% 
    select(1:2) %>% 
    filter(!is.na(airport_passengers)) %>% 
    mutate(date = yearmonth(date)) %>% 
    as_tsibble()
## Using `date` as index variable.

Undersökning av features

Nu kan vi undersöka tidsserien med feasts. Vi kan exempelvis göra en säsongs- och trenddekomposition med funktionen STL() i funktionen model(). Vi ser då att vi har ganska stor säsongsvariation och en uppgående trend.

airport_ts %>% 
    model(STL()) %>%
    components() %>% 
    autoplot()
## Model not specified, defaulting to automatic modelling of the `airport_passengers` variable. Override this using the model formula.

Skapa en prognos

I R har vi möjlighet att specificera modeller för specifika fall, men ofta kan det vara bra att börja med ett automatiskt tillvägagångssätt. Funktionen ETS() skapar (om inget annat anges) automatiskt den bästa prognosmodellen baserat på din data. I paketet fable finns dessutom stöd för flera andra typer av modeller, exempelvis ARIMA().

Nedan anpassar vi en ETS-modell och en Arima-modell och gör sedan en prognos 1 år framåt i tiden.

forecast_modell <- airport_ts %>% 
    model(
    ets = ETS(airport_passengers),
    arima = ARIMA(airport_passengers)
  ) 

forecast_modell %>%
  forecast(h = "1 year") %>% 
    autoplot(airport_ts)

Vilken modell är bäst?

Det finns flera sätt att utvärdera huruvida en prognosmodell är bättre än en annan. Vanligtvis delar man upp data i större träningsdataset som man tränar och utvärderar en modell på och ett testdataset som man sparar till allra sist.

Oavsett hur du lägger upp utvärderingen kan du med paketen vi använder här använda funktionen accuracy(). Vi kan exempelvis utvärdera modellerna på träningsdata.

accuracy(forecast_modell)
## # A tibble: 2 x 9
##   .model .type        ME   RMSE    MAE     MPE  MAPE  MASE    ACF1
##   <chr>  <chr>     <dbl>  <dbl>  <dbl>   <dbl> <dbl> <dbl>   <dbl>
## 1 ets    Training -2974. 52441. 41678. -0.0921  1.20 0.248 -0.0585
## 2 arima  Training  1243. 56912. 41951.  0.0212  1.17 0.249 -0.0831

Vill du läsa mer om hur man utvärderar tidseriemodeller kan jag rekommendera det här kapitlet i Forecasting: Principles and Practice av Rob J. Hyndman och George Athanasopoulos.

Skriva tillbaka till Excel

Baserat på RMSE, MAE och MASE verkar ETS-modellen vara den bästa på träningsdata, så vi väljer att gå vidare med den för den här gången.

Om vi nu vill ha ett resultat likt det vi får från Excels prognosfunktion kan vi enkelt skriva vårt resultat från R till Excel med paketet openxlsx.

library(openxlsx)
forecast_final <- airport_ts %>% 
    model(
    ets = ETS(airport_passengers)
  ) %>%
  forecast(h = "1 year") %>% 
    hilo(level = 95) %>% 
    unnest(`95%`)

write.xlsx(forecast_final, file = paste0("prognos-", Sys.Date(), ".xlsx"), asTable = TRUE)

Resultatet blir då en vanlig tabell i Excel.

Varför göra det här i R?

Prognosfunktionen i Excel är bra om du vill få en snabb uppfattning om din tidsserie. Men i många fall är inte data så tillrättalagt som det här exemplet. I regel behöver en analytiker göra flera transformationer och bearbetningar innan man ens kan anpassa en prognosmodell.

Genom att göra alla de stegen, och själva prognosen, i ett programmeringsspråk som R så sparas all kod i ett skript som du kan exekvera så fort du får ny data och behöver uppdatera prognosen. Det här gör att du i princip kan automatisera hela prognosflödet.

Utöver det här innehåller R tusentals kostnadsfria paket för statistiska beräkningar. I många fall fungerar inte ETS eller Arima-modeller särskilt bra, särskilt om du har data som är mer granulär, exempelvis per vecka, dag eller timme. Då behöver du tillgång till andra typer av modeller, och dessa finns i R.

Prognoser är viktiga och kan ha stor påverkan på din verksamhet. Genom att använda ett programmeringsspråk säkerställer du att dina resultat går att reproducera.