DATA 624: HOMEWORK 6

Author

Pascal hermann Kouogang Tafo

Loading the fpp3 library

library(fpp3)
Warning: package 'fpp3' was built under R version 4.5.3
── Attaching packages ──────────────────────────────────────────── fpp3 1.0.3 ──
✔ tibble      3.3.1     ✔ tsibble     1.2.0
✔ dplyr       1.2.1     ✔ tsibbledata 0.4.1
✔ tidyr       1.3.2     ✔ ggtime      1.0.0
✔ lubridate   1.9.5     ✔ feasts      0.5.0
✔ ggplot2     4.0.3     ✔ fable       0.5.0
Warning: package 'tibble' was built under R version 4.5.2
Warning: package 'dplyr' was built under R version 4.5.3
Warning: package 'tidyr' was built under R version 4.5.2
Warning: package 'lubridate' was built under R version 4.5.2
Warning: package 'ggplot2' was built under R version 4.5.3
Warning: package 'tsibble' was built under R version 4.5.3
Warning: package 'tsibbledata' was built under R version 4.5.3
Warning: package 'ggtime' was built under R version 4.5.3
Warning: package 'feasts' was built under R version 4.5.3
Warning: package 'fabletools' was built under R version 4.5.3
Warning: package 'fable' was built under R version 4.5.3
── Conflicts ───────────────────────────────────────────────── fpp3_conflicts ──
✖ lubridate::date()    masks base::date()
✖ dplyr::filter()      masks stats::filter()
✖ tsibble::intersect() masks base::intersect()
✖ tsibble::interval()  masks lubridate::interval()
✖ dplyr::lag()         masks stats::lag()
✖ tsibble::setdiff()   masks base::setdiff()
✖ tsibble::union()     masks base::union()

EXERCISE 9.1

Figure 9.32 shows the ACFs for 36 random numbers, 360 random numbers and 1,000 random numbers.

  1. Explain the differences among these figures. Do they all indicate that the data are white noise?

We observe a much larger swings in the autocorrelation plot with the series of 36 numbers than the plots with 360 and 1000 observations. It is also clearly visible that as the size of numbers increases, the autocorrelations stay closer to zero and become more stable. In definitive, all three ACF plots looks different with different spikes but they are all consistent and all the spikes stays within the blue dashed area.Therefore, all the figures indicate that the data are white noise.

  1. Why are the critical values at different distances from the mean of zero? Why are the autocorrelations different in each figure when they each refer to white noise?

The critical values at different distances from zero because they depend on the number size. Indeed, Larger numbers generate narrower confidence bounds, while smaller numbers produce wider bounds. The autocorrelations differ in each figure because each ACF plot was produced from different random numbers of white noise, therefore it is normal to expect some variations even though the underlying process is the same.

EXERCISE 9.2

A classic example of a non-stationary series are stock prices. Plot the daily closing prices for Amazon stock (contained in gafa_stock), along with the ACF and PACF. Explain how each plot shows that the series is non-stationary and should be differenced.

A classic example of a non-stationary series are stock prices.

  1. Let’s plot the daily closing prices for Amazon stock (contained in gafa_stock), along with the ACF and PACF.
# Let's visualize the gafa_stock dataset.

head(gafa_stock)
# A tsibble: 6 x 8 [!]
# Key:       Symbol [1]
  Symbol Date        Open  High   Low Close Adj_Close    Volume
  <chr>  <date>     <dbl> <dbl> <dbl> <dbl>     <dbl>     <dbl>
1 AAPL   2014-01-02  79.4  79.6  78.9  79.0      67.0  58671200
2 AAPL   2014-01-03  79.0  79.1  77.2  77.3      65.5  98116900
3 AAPL   2014-01-06  76.8  78.1  76.2  77.7      65.9 103152700
4 AAPL   2014-01-07  77.8  78.0  76.8  77.1      65.4  79302300
5 AAPL   2014-01-08  77.0  77.9  77.0  77.6      65.8  64632400
6 AAPL   2014-01-09  78.1  78.1  76.5  76.6      65.0  69787200
# Let's extract the Amazon stocks from the gafa_stock series

amazon_stock <- gafa_stock |>
  filter(Symbol == "AMZN")
head(amazon_stock)
# A tsibble: 6 x 8 [!]
# Key:       Symbol [1]
  Symbol Date        Open  High   Low Close Adj_Close  Volume
  <chr>  <date>     <dbl> <dbl> <dbl> <dbl>     <dbl>   <dbl>
1 AMZN   2014-01-02  399.  399.  394.  398.      398. 2137800
2 AMZN   2014-01-03  398.  403.  396.  396.      396. 2210200
3 AMZN   2014-01-06  396.  397   388.  394.      394. 3170600
4 AMZN   2014-01-07  395.  398.  394.  398.      398. 1916000
5 AMZN   2014-01-08  398.  403   396.  402.      402. 2316500
6 AMZN   2014-01-09  404.  407.  398.  401.      401. 2103000
# Let's plot the daily closing prices of Amazon stock

amazon_stock |> autoplot(Close) +
  labs(title="Daily Amazon stocks closing prices",
       y= "Prices in USD")

# Let's plot the ACF of the daily closing prices of Amazon stock

amazon_stock |> 
  ACF(Close) |>
  autoplot() +
  labs(title="ACF of Amazon stocks closing prices",
       y= "Autocorrelation")
Warning: Provided data has an irregular interval, results should be treated
with caution. Computing ACF by observation.

# Let's plot the PACF of the daily closing prices of Amazon stock

amazon_stock |> 
  PACF(Close) |>
  autoplot() +
  labs(title="PACF of Amazon stocks closing prices",
       y="Partial Autocorrelation")
Warning: Provided data has an irregular interval, results should be treated
with caution. Computing ACF by observation.

Results

The daily closing Amazon stocks prices plot shows a changing level rules of the series in 2018 comparing to 2014.It also exhibits a persistent upward trend throughout 2014-2018 and periods of increasing and decreasing variability. The Autocorrelation plot shows spikes that all go out of the 95% acf blue dashed threshold bounds.The acf spike at lag1 is close to 1 and the rest decreases very slowly which the data is non stationary. The partially autocorrelation (PACF) plot shows a single very large spike at lag1 equivalent to 1 while other lags drop quickly and are oscillating around zero.

Giving the results of these three plots, we conclude that the series is non-stationary, therefore differencing them is necessary.

  1. Let’s plot the difference of the daily closing Amazon stocks prices, the ACF and the PACF of this series.
# Let's create and add the first difference column to the Amazon closing prices data.

amazon_price_diff <- amazon_stock |>
  mutate(diff_closing_price = difference(Close) )


# Let's plot the difference of the daily Amazon closing prices

amazon_price_diff |> autoplot(diff_closing_price) +
  labs(title="First difference of Amazon closing prices",
       y= "Daily Price Change in USD")
Warning: Removed 1 row containing missing values or values outside the scale range
(`geom_line()`).

# Let's plot the ACF of differenced daily Amazon closing prices

amazon_price_diff |> 
  ACF(diff_closing_price) |>
  autoplot() +
  labs(title="ACF of First Difference of Amazon closing prices")
Warning: Provided data has an irregular interval, results should be treated
with caution. Computing ACF by observation.

# Let's plot the PACF of differenced Amazon closing prices 

amazon_price_diff |> 
  PACF(diff_closing_price) |>
  autoplot() +
  labs(title="PACF of First Difference of Amazon closing prices")
Warning: Provided data has an irregular interval, results should be treated
with caution. Computing ACF by observation.

Interpretation

We observe that the plot of the first difference of Amazon closing prices centers the stocks price changes which turn to be stabilized around the mean of zero. Moreover the ACF and PACF plot of the first difference of amazon closing helps us migrate more towards a white noise (even though it is not perfect) because the majority of spike are within the 95% blue dashed threshold bounds.

Exercise 9.3 :

  1. For the following series, find an appropriate Box-Cox transformation and order of differencing in order to obtain stationary data.
    1. Turkish GDP from global_economy.
    2. Accommodation takings in the state of Tasmania from aus_accommodation.
    3. Monthly sales from souvenirs.
  1. For the Turkish GDP from ‘global_economy’ series,Let’s find an appropriate Box-Cox transformation and order of differencing in order to obtain stationary data.
# Let's extract the data of interest

turkish_gdp <- global_economy |>
  filter(Country == "Turkey") |>
  select(Country,Year,GDP)

head(turkish_gdp)
# A tsibble: 6 x 3 [1Y]
# Key:       Country [1]
  Country  Year          GDP
  <fct>   <dbl>        <dbl>
1 Turkey   1960 13995067818.
2 Turkey   1961  8022222222.
3 Turkey   1962  8922222222.
4 Turkey   1963 10355555556.
5 Turkey   1964 11177777778.
6 Turkey   1965 11944444444.
# Let's visualize the plot of the turkish GDP data

turkish_gdp |>
  autoplot() +
  labs(title="The yearly Turkish GDP ")
Plot variable not specified, automatically selected `.vars = GDP`

# Let's visualize the ACF plot of the turkish GDP data

turkish_gdp |>
  ACF(GDP) |>
  autoplot() +
  labs(title="The yearly Turkish GDP ")

# Let's estimate the guerrero parameter lambda to find the appropriate box-Cox transformation.

lambda_turkey <- turkish_gdp |>
  features(GDP, features = guerrero) |>
  pull(lambda_guerrero)
  
lambda_turkey
[1] 0.1572187

Result:

The plot shows that the Turkish GDP exhibit a strong exponential growth with variance growing over decades especially after 2000. Also, lambda is equal to 0.15 which can be approximate to 0. A log transformation is needed to stabilize the spread.

Now, let’s find the order of difference to make our transformed series stationary. We will use the unitroot_ndiffs function to estimate the order differences because our data is non seasonal.

# let's compute the turkish gdp order of difference

turkish_order_diff <- turkish_gdp |>
  mutate(turkish_gdp_tf = box_cox(GDP, lambda_turkey)) |>
  features(turkish_gdp_tf, unitroot_ndiffs)

turkish_order_diff
# A tibble: 1 × 2
  Country ndiffs
  <fct>    <int>
1 Turkey       1
# Let's plot the Turkish GDP: log/Box-Cox transformation and first difference

turkish_gdp |>
  mutate(turkish_gdp_tf = box_cox(GDP, lambda_turkey)) |>
  autoplot(difference(turkish_gdp_tf)) +
  labs(
    title = "Differenced Turkish GDP",
    y = "Differenced transformed GDP"
  )
Warning: Removed 1 row containing missing values or values outside the scale range
(`geom_line()`).

# let's compute the ACF plot 

turkish_gdp |>
  mutate(turkish_gdp_tf = box_cox(GDP, lambda_turkey)) |>
  ACF(difference(turkish_gdp_tf)) |>
  autoplot() +
  labs(
    title = " Differenced Turkish GDP",
  )

Interpretation:

The Turkish GDP series is a non seasonal annual series that becomes stationary after the box transformation which stabilize the variance and requires only the first difference to help stabilizing the mean.

b) Let’s find an appropriate Box-Cox transformation and order of difference in order to obtain stationary data for the Accommodation takings in the state of Tasmania from aus_accommodation

head(aus_accommodation)
# A tsibble: 6 x 5 [1Q]
# Key:       State [1]
     Date State                        Takings Occupancy   CPI
    <qtr> <chr>                          <dbl>     <dbl> <dbl>
1 1998 Q1 Australian Capital Territory    24.3        65  67  
2 1998 Q2 Australian Capital Territory    22.3        59  67.4
3 1998 Q3 Australian Capital Territory    22.5        58  67.5
4 1998 Q4 Australian Capital Territory    24.4        59  67.8
5 1999 Q1 Australian Capital Territory    23.7        58  67.8
6 1999 Q2 Australian Capital Territory    25.4        61  68.1
# Let's extract the data of interest

tasmania <- aus_accommodation |>
  filter(State == "Tasmania") |>
  select(Date,State,Takings)

head(tasmania)
# A tsibble: 6 x 3 [1Q]
# Key:       State [1]
     Date State    Takings
    <qtr> <chr>      <dbl>
1 1998 Q1 Tasmania    28.7
2 1998 Q2 Tasmania    19.0
3 1998 Q3 Tasmania    16.1
4 1998 Q4 Tasmania    25.9
5 1999 Q1 Tasmania    28.4
6 1999 Q2 Tasmania    20.1
# Let's visualize the Accommodation takings in Tasmania

tasmania |>
  autoplot() +
  labs(title="The Quarterly Accommodation takings in Tasmania ")
Plot variable not specified, automatically selected `.vars = Takings`

# Let's estimate the guerrero parameter lambda to find the appropriate box-Cox transformation.

lambda_tasmania <- tasmania |>
  features(Takings, features = guerrero) |>
  pull(lambda_guerrero)
  
lambda_tasmania
[1] 0.001819643

Results

This series shows a quarterly seasonal pattern and a size that grows with the level. Also Lambda is equal to 0.0018 which can be approximate to 0, so a log transformation is necessary. We will transformed the series and find the order of difference to make the series stationary using the unitroot_nsdiffs function since the series is seasonal.

Now, let’s find the order of difference to make our transformed series stationary. Since the data is quarterly, we will first test the seasonal differences, following by the regular differences.

# Let's check the seasonal differences needed (D)

tasmania_order_diff <- tasmania |>
  mutate(tasmania_trans = box_cox(Takings, lambda_tasmania)) |>
  features(tasmania_trans, unitroot_nsdiffs)

tasmania_order_diff
# A tibble: 1 × 2
  State    nsdiffs
  <chr>      <int>
1 Tasmania       1
# Let's check the regular differences needed (d) after seasonal differencing

tasmania |>
  mutate(tasmania_trans = box_cox(Takings, lambda_tasmania)) |>
  mutate(d_seasonal = difference(tasmania_trans, 4)) |>
  features(d_seasonal, unitroot_ndiffs)
# A tibble: 1 × 2
  State    ndiffs
  <chr>     <int>
1 Tasmania      0

result

The result indicates that the transformed series requires one seasonal difference (D= 1) because of strong quarterly seasonality, but no regular difference (d=0).

# Let's plot the Tasmania transformed of the differenced accommodation takings

tasmania |>
  mutate(tasmania_trans = box_cox(Takings, lambda_tasmania)) |>
  autoplot(difference(tasmania_trans)) +
  labs(
    title = "Differenced in Tasmania Accommodation Takings"
  )
Warning: Removed 1 row containing missing values or values outside the scale range
(`geom_line()`).

# Let's plot the quarterly seasonal difference

tasmania |>
  mutate(tasmania_trans = box_cox(Takings, lambda_tasmania)) |>
  autoplot(difference(tasmania_trans, 4)) +
  labs(
    title = "Quarterly seasonal Differenced Accomodation Takings",
  )
Warning: Removed 4 rows containing missing values or values outside the scale range
(`geom_line()`).

# ACF

tasmania |>
  mutate(tasmania_trans = box_cox(Takings, lambda_tasmania)) |>
  ACF(difference(tasmania_trans, 4)) |>
  autoplot() +
  labs(title = "seasonal change in Accommodation Takings")

c) Let’s find an appropriate Box-Cox transformation and order of differencing in order to obtain stationary data for Monthly sales from souvenirs.

# Let's check the souvenirs dataset

head(souvenirs,12)
# A tsibble: 12 x 2 [1M]
      Month  Sales
      <mth>  <dbl>
 1 1987 Jan  1665.
 2 1987 Feb  2398.
 3 1987 Mar  2841.
 4 1987 Apr  3547.
 5 1987 May  3753.
 6 1987 Jun  3715.
 7 1987 Jul  4350.
 8 1987 Aug  3566.
 9 1987 Sep  5022.
10 1987 Oct  6423.
11 1987 Nov  7601.
12 1987 Dec 19756.
# Let's plot the monthly sales from souvenirs

souvenirs |>
  autoplot() +
  labs(title="The Monthly sales from souvenirs")
Plot variable not specified, automatically selected `.vars = Sales`

# Let's estimate the guerrero parameter lambda to find the appropriate box-Cox transformation.

lambda_souvenirs <- souvenirs |>
  features(Sales, features = guerrero) |>
  pull(lambda_guerrero)
  
lambda_souvenirs
[1] 0.002118221

Result

The plot of the monthly exhibit strong December peaks that grow over time and, a surge at the end of the year. This leads to multiplicative seasonality, and lambda is approximately equal to 0 so we will apply a log transformation to our series.

Let’s find the order of difference to make our transformed series stationary.

Since we have monthly seasonal data (m=12 observations), we will first test the seasonal differences , following by the regular differences.

# Let's check the seasonal order differences needed (D)

souvenirs |>
  mutate(monthly_sales_tf = box_cox(Sales, lambda_souvenirs)) |>
  features(monthly_sales_tf, unitroot_nsdiffs)
# A tibble: 1 × 1
  nsdiffs
    <int>
1       1
# Let's now check the regular order differences needed (d) after seasonal order differences

souvenirs |>
  mutate(monthly_sales_tf = box_cox(Sales, lambda_souvenirs)) |>
  mutate(d_seasonal = difference(monthly_sales_tf, 12)) |>
  features(d_seasonal, unitroot_ndiffs)
# A tibble: 1 × 1
  ndiffs
   <int>
1      0
# Let's plot the transformed monthly sales

souvenirs |>
   mutate(monthly_sales_tf = box_cox(Sales, lambda_souvenirs)) |>
  autoplot(monthly_sales_tf) +
  labs(
    title = "Transformed Monthly Souvenir Sales",
    y = "Transformed sales"
  )

# Let's plot the seasonal difference

souvenirs |>
  mutate(monthly_sales_tf = box_cox(Sales, lambda_souvenirs)) |>
  autoplot(difference(monthly_sales_tf, 12)) +
  labs(
    title = "Seasonally Differenced Souvenir Sales",
    y = "Seasonally differenced transformed sales"
  )
Warning: Removed 12 rows containing missing values or values outside the scale range
(`geom_line()`).

# ACF

souvenirs |>
  mutate(monthly_sales_tf = box_cox(Sales, lambda_souvenirs)) |>
  ACF(difference(monthly_sales_tf, 12)) |>
  autoplot() +
  labs(title = "seasonal change in monthly sales")

Exercise 9.5 :

For your retail data (from Exercise 7 in Section 2.10), find the appropriate order of differencing (after transformation if necessary) to obtain stationary data.

a) Let’s look at the data.

set.seed(12345678)

myseries <- aus_retail |>
  filter(`Series ID` == sample(aus_retail$`Series ID`, 1))
head(myseries)
# A tsibble: 6 x 5 [1M]
# Key:       State, Industry [1]
  State              Industry                      `Series ID`    Month Turnover
  <chr>              <chr>                         <chr>          <mth>    <dbl>
1 Northern Territory Clothing, footwear and perso… A3349767W   1988 Apr      2.3
2 Northern Territory Clothing, footwear and perso… A3349767W   1988 May      2.9
3 Northern Territory Clothing, footwear and perso… A3349767W   1988 Jun      2.6
4 Northern Territory Clothing, footwear and perso… A3349767W   1988 Jul      2.8
5 Northern Territory Clothing, footwear and perso… A3349767W   1988 Aug      2.9
6 Northern Territory Clothing, footwear and perso… A3349767W   1988 Sep      3  
# Let's plot the data to visualize the pattern

myseries |>
  autoplot(Turnover) +
  labs(title= "The original retail turnover ")

myseries |>
  ACF(Turnover) |>
  autoplot() +
  labs(title= "The original retail turnover ")

The original plot shows a strong positive trend with a variance that grows with the level of our series and it presents a seasonality pattern. The ACF spikes are all beyond the 95% blue dashed bound, so our data is non stationary.

b) Let’s find the appropriate box-cox transformation to stabilize our variance using the Guerrero method.

# Let's find the value of lambda

lambda <- myseries |>
  features(Turnover, features= guerrero) |>
  pull(lambda_guerrero)

lambda
[1] 0.08303631

Result

lambda is equal to 0.08 which can be approximate to 0,therefore a log transformation is necessary to stabilize the variation throughout the series.

c) Let’s apply the transformation and find the correct order difference.

Since we have monthly seasonal data (m=12 observations), we will first test the seasonal differences , following by the regular differences.

# let's apply the transformation 

myseries <- myseries |>
  mutate(Turnover_trans = box_cox(Turnover, lambda))

# Let's test for seasonal unit root which check for the strength of seasonality.

myseries |>
  features(Turnover_trans, unitroot_nsdiffs) |>
  select(nsdiffs)
# A tibble: 1 × 1
  nsdiffs
    <int>
1       1

Result

The seasonal difference for our transformed series is 1 at lag 12.

# let's test for first differencing on our seasonal differenced series

myseries |>
  mutate(Turnover_sdiff = difference(Turnover_trans, 12)) |>
  features(Turnover_sdiff, unitroot_ndiffs)
# A tibble: 1 × 3
  State              Industry                                            ndiffs
  <chr>              <chr>                                                <int>
1 Northern Territory Clothing, footwear and personal accessory retailing      0
# Let's test the KPSS stationarity 

myseries |>
  mutate(Turnover_diff = difference(difference(Turnover_trans, 12), 1)) |>
  features(Turnover_diff, unitroot_kpss) |>
  select(kpss_pvalue)
# A tibble: 1 × 1
  kpss_pvalue
        <dbl>
1         0.1

Conclusion.

The KPSS test p-value is 0.1 greater than 0.05 meaning failing to reject the null hypothesis of stationarity. The log transformation of our data at the first order of diffference is stationary.

Exercise 9.6

Simulate and plot some data from simple ARIMA models.

a) Use the following R code to generate data from an AR(1) model with ϕ1=0.6 and σ2=1. The process starts with y1=0.

y <- numeric(100)
e <- rnorm(100)
for (i in 2:100) {
  y[i] <- 0.6 * y[i - 1] + e[i]
}
sim <- tsibble(idx = seq_len(100), y = y, index = idx)

**b) Let’s produce a time plot for the series. How does the plot change as you change ϕ1?

sim |>
  autoplot(y) +
  labs(title= "simulated AR(1) model ",
       x= "timeindex", y="y")

result

  • When ϕ1 is zero and our constant equals zero then the data will look like white noise.
  • When ϕ1 move close to 1 then the data gets smoother and wanders in longer runs above and below zero.
  • When ϕ1 equals 1 and the constant does not equal zero then the data will look like a random walk with drift.
  • When ϕ1 is negative then the series tends to oscillate around the mean.

c) Write your own code to generate data from an MA(1) model with θ1=0.6 and σ2=1.

e <- rnorm(100)
y_MA <- numeric(100)
y_MA[1] <- e[1]         # For t=1, e[0] = 0

for (i in 2:100) {
  y_MA[i] <- e[i] + 0.6 * e[i - 1]
}

sim_MA1 <- tsibble(idx = seq_len(100), y = y_MA, index = idx)
head(sim_MA1)
# A tsibble: 6 x 2 [1]
    idx      y
  <int>  <dbl>
1     1  0.294
2     2  0.481
3     3 -0.230
4     4 -0.368
5     5 -0.460
6     6 -0.634

d) Let’s Produce a time plot for the series. How does the plot change as you change θ1

sim_MA1 |> 
  autoplot(y) +
  labs(title = "Simulated MA(1) with θ1==0.6",
       x = "Time index", y = "y")

Interpretation

The effect here when changing θ1 is less impactful. - When θ1=0, the series looks identical to Gaussian white noise. - When θ1 is positive and increases , the series is slightly more smoothing since the nearest observations share a positive fraction of the previous one. - when θ1 is negative and decreases,nearest points show negative correlation.

e)Let’s generate data from an ARMA(1,1) model with ϕ1=0.6, θ1=0.6 and σ2=1.

This model combines autoregressive and moving average parameters.

e <- rnorm(100)
y_ARMA <- numeric(100)
y_ARMA[1] <- e[1]

for (i in 2:100) {
  y_ARMA[i] <- 0.6 * y_ARMA[i - 1] + e[i] + 0.6 * e[i - 1]
}

sim_ARMA <- tsibble(idx = seq_len(100), y = y_ARMA, index = idx)
head(sim_ARMA)
# A tsibble: 6 x 2 [1]
    idx      y
  <int>  <dbl>
1     1 -1.09 
2     2 -0.616
3     3  0.443
4     4 -0.686
5     5 -0.196
6     6  1.04 

f)Let’s generate data from an AR(2) model with ϕ1=−0.8, ϕ2=0.3 and σ2=1. (Note that these parameters will give a non-stationary series.)

This is an autoregressive model of order 2.

e <- rnorm(100)
y_AR2 <- numeric(100)
y_AR2[1] <- e[1]
y_AR2[2] <- -0.8 * y_AR2[1] + e[2]

for (i in 3:100) {
  y_AR2[i] <- -0.8 * y_AR2[i - 1] + 0.3 * y_AR2[i - 2] + e[i]
}

sim_AR2 <- tsibble(idx = seq_len(100), y = y_AR2, index = idx)
head(sim_AR2)
# A tsibble: 6 x 2 [1]
    idx      y
  <int>  <dbl>
1     1  0.257
2     2 -0.480
3     3  1.35 
4     4 -0.695
5     5  0.912
6     6 -1.42 

**g) Let’s graph the latter two series and compare them

library(patchwork)

Plot_ARMA <- sim_ARMA |> 
  autoplot(y) +
  labs(title = "ARMA(1,1): ϕ1 = 0.6, θ1=0.6",
       subtitle = "Stationary Process",
       x = "Time index", y = "y")


Plot_AR2 <- sim_AR2 |> 
  autoplot(y) +
  labs(title = "AR(2): ϕ1 == -0.8, ϕ2= 0.3",
       subtitle = "Non-Stationary Process",
       x = "Time index", y = "y")

# Combine plots vertically

Plot_ARMA / Plot_AR2

Results

The ARMA(1,1) series is stationary,fluctuate around 0 and stays between -4 and 4. It shows moderate smoothness. The AR(2) series is non-stationary and exhibit rapid oscillations and changing variability.

Exercise 9.7

Consider aus_airpassengers, the total number of passengers (in millions) from Australian air carriers for the period 1970-2011.

a) Use ARIMA() to find an appropriate ARIMA model. What model was selected? Check that the residuals look like white noise. Plot forecasts for the next 10 periods.

# check the data

head(aus_airpassengers)
# A tsibble: 6 x 2 [1Y]
   Year Passengers
  <dbl>      <dbl>
1  1970       7.32
2  1971       7.33
3  1972       7.80
4  1973       9.38
5  1974      10.7 
6  1975      11.1 
# Let's the Arima auto model to the series

fit_auto <- aus_airpassengers |> 
  model(Auto_Arima = ARIMA(Passengers))

report(fit_auto)
Series: Passengers 
Model: ARIMA(0,2,1) 

Coefficients:
          ma1
      -0.8963
s.e.   0.0594

sigma^2 estimated as 4.308:  log likelihood=-97.02
AIC=198.04   AICc=198.32   BIC=201.65
# Let's check the residuals

gg_tsresiduals(fit_auto)

Result

The innovation residuals fluctuate around zero with a fairly steady variance, even though the variance increases in later years. The ACF behave like white noise because all the spikes stay within the 95% blue dashed critical thresholds and a Ljung_Box test give a p-vale greater than 0.05.

# Let's plot forecasts for the next 10 periods

fit_auto |> 
  forecast(h = 10) |> 
  autoplot(aus_airpassengers)

Result.

The forecast produces a straight continue upward line with prediction intervals that expand noticeably.

b) Write the model in terms of the backshift operator.

For an ARIMA(0,2,1) process without constant, we have:

(1-B)^2*yt = (1+ θ1B)εt

when susbtituting θ1 with -0.8963 and expanding the difference operator (1-B)^2, we obtain:

yt - 2\[y_t - 2y_{t-1} + y_{t-2} = \varepsilon_t - 0.8963\varepsilon_{t-1}\]

c) Let’s Plot forecasts from an ARIMA(0,1,0) model with drift and compare these to part a.

fit_010 <- aus_airpassengers |> 
  model(arima010 = ARIMA(Passengers ~ 1 + pdq(0, 1, 0)))

report(fit_010)
Series: Passengers 
Model: ARIMA(0,1,0) w/ drift 

Coefficients:
      constant
        1.4191
s.e.    0.3014

sigma^2 estimated as 4.271:  log likelihood=-98.16
AIC=200.31   AICc=200.59   BIC=203.97
fit_010 |> 
  forecast(h = 10) |> 
  autoplot(aus_airpassengers)

Interpretation

The central forecasts of both are very similar since they both extrapolate a linear trend. The difference comes from the prediction intervals where the ARIMA(0,1,0) model with drift one is narrower because single differencing accumulates variance proportionally to the forecast horizon h, whereas double differencing in ARIMA(0,2,1) causes variance to grow roughly as h^3.

d) Let’s plot forecasts from an ARIMA(2,1,2) model with drift and compare these to parts a and c. Remove the constant and see what happens.

# Let's fit the ARIMA(2,1,2) model with drift

fit_AR212_drift <- aus_airpassengers |> 
  model(arima212 = ARIMA(Passengers ~ 1 + pdq(2, 1, 2)))

report(fit_AR212_drift)
Series: Passengers 
Model: ARIMA(2,1,2) w/ drift 

Coefficients:
          ar1      ar2     ma1     ma2  constant
      -0.5518  -0.7327  0.5895  1.0000    3.2216
s.e.   0.1684   0.1224  0.0916  0.1008    0.7224

sigma^2 estimated as 4.031:  log likelihood=-96.23
AIC=204.46   AICc=206.61   BIC=215.43
# Let's forecast the ARIMA(2,1,2) model with drift

fit_AR212_drift |> 
  forecast(h = 10) |> 
  autoplot(aus_airpassengers)

# Let's fit the ARIMA(2,1,2) Without constant

fit_AR212_no_const <- aus_airpassengers |> 
  model(arima212_no_c = ARIMA(Passengers ~ 0 + pdq(2, 1, 2)))
Warning: 1 error encountered for arima212_no_c
[1] non-stationary AR part from CSS
report(fit_AR212_no_const)
Series: Passengers 
Model: NULL model 
NULL model

Result

For the ARIMA(2,1,2) model with drift, the forecasts are closer to the ones in part a and c because it exhibit a linear upward trend with the AR/MA terms that changes only couple of first few steps. For the ARIMA(2,1,2) model with drift without constant,we have a warning about the fit non-stationary AR part from CSS.

e) Let’s plot forecasts from an ARIMA(0,2,1) model with a constant. What happens?

# fit the ARIMA(0,2,1) model with a constant

fit_AR021_const <- aus_airpassengers |> 
  model(arima021_c = ARIMA(Passengers ~ 1 + pdq(0, 2, 1)))
Warning: Model specification induces a quadratic or higher order polynomial trend.  This
is generally discouraged, consider removing the constant or reducing the number
of differences.
report(fit_AR021_const)
Series: Passengers 
Model: ARIMA(0,2,1) w/ poly 

Coefficients:
          ma1  constant
      -1.0000    0.0571
s.e.   0.0585    0.0213

sigma^2 estimated as 3.855:  log likelihood=-95.1
AIC=196.21   AICc=196.79   BIC=201.63
# Let's forecasts

fit_AR021_const |> 
  forecast(h = 10) |> 
  autoplot(aus_airpassengers)

Result

With second order difference, the constant adds a quadratic trend to the forecasts. Hence, the forecasts will curve sharply upward instead of maintaining a linear trend which will force this model to likely wrongly forecasts as the horizon groms.

Exercise 9.8 :

For the United States GDP series (from global_economy):

a) If necessary, find a suitable Box-Cox transformation for the data;

# Let's first check the united States GDP series

USA_gdp <- global_economy |>
  filter(Country == "United States") |>
  select(Year,GDP)
head(USA_gdp)
# A tsibble: 6 x 2 [1Y]
   Year          GDP
  <dbl>        <dbl>
1  1960 543300000000
2  1961 563300000000
3  1962 605100000000
4  1963 638600000000
5  1964 685800000000
6  1965 743700000000
# Let's plot the data

USA_gdp |> autoplot(GDP) +
  labs(title="The Yearly United States GDP")

Interpretation

The USA GDP plot exhibit a strong growth pattern over time and the variation increases as the level rises, as consequence we believe a Box-Cox transformation is necessary to stabilize our series.

# Let's check for the suitable Box-Cox transformation

usa_lambda <- USA_gdp |>
  features(GDP, features = guerrero ) |>
  pull(lambda_guerrero)

usa_lambda
[1] 0.2819443
# let's plot the transformed GDP series

USA_gdp |>
  autoplot(box_cox(GDP, usa_lambda)) +
  labs(title= "Box-Cox transformation of United GDP",
       y = "Transformed GDP" )

Interpretation

We observe that the Box-Cox transformation helped us reduce the effect of the large variations between early and recent GDP values.

b) Fit a suitable ARIMA model to the transformed data using ARIMA();

# Let's fit the automated ARIMA model() first on the transformed series.

USA_gdp_fit <- USA_gdp |>
  model(auto_arima = ARIMA(box_cox(GDP, usa_lambda)))

report(USA_gdp_fit)
Series: GDP 
Model: ARIMA(1,1,0) w/ drift 
Transformation: box_cox(GDP, usa_lambda) 

Coefficients:
         ar1  constant
      0.4586  118.1822
s.e.  0.1198    9.5047

sigma^2 estimated as 5479:  log likelihood=-325.32
AIC=656.65   AICc=657.1   BIC=662.78

Result

The ARIMA(1,1,0) with drift is our selected model when fitting an automated ARIMA model.

c) Let’s try some other plausible models by experimenting with the orders chosen

# Let's fit with other ARIMA models

USA_gdp_fit <- USA_gdp |>
  model(
    auto_arima = ARIMA(box_cox(GDP, usa_lambda)),
    arima_010 = ARIMA(box_cox(GDP, usa_lambda) ~ pdq(0,1,0)),
    arima_011 = ARIMA(box_cox(GDP, usa_lambda) ~ pdq(0,1,1)),
    arima_110 = ARIMA(box_cox(GDP, usa_lambda) ~ pdq(1,1,0)),
    arima_111 = ARIMA(box_cox(GDP, usa_lambda) ~ pdq(1,1,1)),
    arima_210 = ARIMA(box_cox(GDP, usa_lambda) ~ pdq(2,1,0)),
  )

d) Let’s choose what we think is the best model and check the residual diagnostics

First we will have to compare all those fitted ARIMA models and select the best based on its AICc.

i) let’s compare the models

# Let's compare the ARIMA models

glance(USA_gdp_fit) |>
  select(.model, AIC, AICc, BIC) |>
  arrange(AICc)
# A tibble: 6 × 4
  .model       AIC  AICc   BIC
  <chr>      <dbl> <dbl> <dbl>
1 auto_arima  657.  657.  663.
2 arima_110   657.  657.  663.
3 arima_011   659.  659.  665.
4 arima_111   659.  659.  667.
5 arima_210   659.  659.  667.
6 arima_010   668.  668.  672.

ii) Let’s pick what we think is the best model and examine the residuals diagnostics

The best model should be the one with the lowest AICc value which in this case is the auto_arima model.

# The best model

best_USA_gdp_fit <- USA_gdp |>
  model(
    best_arima = ARIMA(box_cox(GDP, usa_lambda))
  )

# Let's check the residuals diagnostics plot

best_USA_gdp_fit |> gg_tsresiduals()

Results

The residuals time plot fluctuate almost evenly around zero with the deepest decline around 2009 and 2010. Also, the acf plot exhibit no autocorrelation spikes beyond the 95% blue dashed threshold bounds. Moreover, despite the the residuals around -275 which can be seen as an outlier, the entire distribution seems approximately symmetric around 0. For more information,we will compute Ljung-Box test for residuals autocorrelation to test the p-value before producing our forecast

augment(best_USA_gdp_fit) |>
  features(.innov,ljung_box, lag=10, dof = 1)
# A tibble: 1 × 3
  .model     lb_stat lb_pvalue
  <chr>        <dbl>     <dbl>
1 best_arima    3.81     0.923

Our test returns p-value well above 0.05, hence fails to reject the null hypothesis of independence, therefore no significant autocorrelation remains.

e) Let’s produce forecasts of your fitted model. Do the forecasts look reasonable?

# Forecast our best ARIMA model 10 years ahead

forecast_best_model <- best_USA_gdp_fit |>
  forecast(h= 10) 

# let's plot it

forecast_best_model |> autoplot(USA_gdp) +
  labs(title=" The USA GDP ARIMA(1,1,0) with drift forecast")

Interpretation

The forecast looks reasonable because it appears to follow the historical growth pattern of GDP observe in previous observations with the long term upward trend.

f) Compare the results with what you would obtain using ETS() (with no transformation).

First we forecast our series using ETS() model (with no transformation).

# Let's forecast ETS model without transformation

forecast_USA_gdp_ETS <- USA_gdp |>
  model(ETS_model= ETS(GDP)) |>
  forecast(h =10)

# Let's plot

forecast_USA_gdp_ETS |> autoplot(USA_gdp) +
  labs(title= "ETS Forecasts for USA GDP")

We will then compare the ARIMA and ETS models.

# Let's fit both models

usa_gdp_comparison <- USA_gdp |>
  model(
     best_arima = ARIMA(box_cox(GDP, usa_lambda)),
     ETS_model= ETS(GDP)
  )

# Let's forecast both  and plot them 10 years ahead

forecast_usa_gdp_comparison <- usa_gdp_comparison |> 
  forecast(h=10) |>
  autoplot(USA_gdp) +
  labs(title= "USA GDP forecast : ARIMA vs ETS")

forecast_usa_gdp_comparison

Interpretation:

The result shows that they both produce a long and strong almost identical upward trend with the one from the ARIMA that looks more steady.