Part I

library(fable)
## Loading required package: fabletools
## Registered S3 method overwritten by 'tsibble':
##   method               from 
##   as_tibble.grouped_df dplyr
library(fabletools)
library(feasts)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(tsibble)
## 
## Attaching package: 'tsibble'
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, union
library(ggplot2)
library(fredr)

fredr_set_key("430508d0ad1df25ecddc34d5581dafc8")


unrate <- fredr("UNRATE", 
             observation_start = as.Date("1948-01-01"), 
             observation_end = as.Date("2025-08-01") ) |> 
  mutate(Month = yearmonth(date), value) |>
  as_tsibble(index = Month) 

autoplot(unrate)
## Plot variable not specified, automatically selected `.vars = value`

unrate |>
  gg_tsdisplay(difference(value), plot_type='partial')
## Warning: `gg_tsdisplay()` was deprecated in feasts 0.4.2.
## ℹ Please use `ggtime::gg_tsdisplay()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_point()`).

##tried (1,1,0) and (0,1,1) because the ACF and PACF dont show strong movements and dont hit the blue lines. 

unrate_fit <- unrate |>
  model(arima110 = ARIMA(value ~ pdq(1,1,0)),
        arima011 = ARIMA(value ~ pdq(0,1,1)),
        stepwise = ARIMA(value),
        search = ARIMA(value, stepwise=FALSE))

glance(unrate_fit) |> arrange(AICc) |> select(.model:BIC)
## # A tibble: 4 × 6
##   .model   sigma2 log_lik   AIC  AICc   BIC
##   <chr>     <dbl>   <dbl> <dbl> <dbl> <dbl>
## 1 stepwise  0.171   -498. 1003. 1003. 1017.
## 2 search    0.171   -498. 1005. 1005. 1030.
## 3 arima011  0.172   -501. 1006. 1006. 1016.
## 4 arima110  0.172   -501. 1006. 1006. 1016.
#the AICs for both models are pretty large. 


#Setting up the data to have a test and train sample with 80%/20% 
split_index <- floor(0.8 * nrow(unrate)) 
train <- unrate[1:split_index, ] 
test <- unrate[(split_index + 1):nrow(unrate), ] 

autoplot(train)
## Plot variable not specified, automatically selected `.vars = value`

#The ARIMA model gives Model: ARIMA(1,1,2)(2,0,1)[12], this AIC is much smaller than the ones I used. The model paramters selected were differnt from my manual selection. 

fit <- train|>
  model(ARIMA(value))
report(fit)
## Series: value 
## Model: ARIMA(1,1,2)(2,0,1)[12] 
## 
## Coefficients:
##          ar1      ma1     ma2    sar1     sar2     sma1
##       0.8355  -0.8527  0.2391  0.4795  -0.0863  -0.7149
## s.e.  0.0365   0.0499  0.0370  0.0992   0.0536   0.0948
## 
## sigma^2 estimated as 0.03701:  log likelihood=172.02
## AIC=-330.05   AICc=-329.9   BIC=-297.77
fc<- fit |> forecast(h=nrow(test)) 

fc |>
  autoplot(train) +
  labs(y = "Unemployment Rate", title = "Unemployment")

acc <- accuracy(object = fc, test ) |>
  select(.model, ME, MPE, RMSE, MAE, MAPE ) 

library(kableExtra) # Print with knitr::kable 
## 
## Attaching package: 'kableExtra'
## The following object is masked from 'package:dplyr':
## 
##     group_rows
kable(acc, caption = "Forecast Accuracy Metrics") |> 
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), 
                full_width = FALSE)
Forecast Accuracy Metrics
.model ME MPE RMSE MAE MAPE
ARIMA(value) -2.198506 -55.07731 2.937776 2.48955 57.68755
unrate |>
  ACF(value) |>
  autoplot()

unrate |>
  PACF(value) |>
  autoplot()

fit |>
  gg_tsresiduals()
## Warning: `gg_tsresiduals()` was deprecated in feasts 0.4.2.
## ℹ Please use `ggtime::gg_tsresiduals()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

##plot shows it is acting as white noise. 

Part II

#median CPI
mcpi <- fredr("MEDCPIM158SFRBCLE", 
             observation_start = as.Date("1948-01-01"), 
             observation_end = as.Date("2025-08-01") ) |> 
  mutate(Month = yearmonth(date), value) |>
  as_tsibble(index = Month) 

autoplot(mcpi)
## Plot variable not specified, automatically selected `.vars = value`

#seasonal difference 
mcpi |>
  gg_tsdisplay(difference(value, 12), plot_type='partial')
## Warning: Removed 12 rows containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 12 rows containing missing values or values outside the scale range
## (`geom_point()`).

##tried (1,1,0) and (0,1,1) because the ACF and PACF dont show strong movements and dont hit the blue lines. 

mcpi_fit <- mcpi |>
  model(arima110 = ARIMA(value ~ pdq(1,1,0)),
        arima011 = ARIMA(value ~ pdq(0,1,1)),
        stepwise = ARIMA(value),
        search = ARIMA(value, stepwise=FALSE))

glance(mcpi_fit) |> arrange(AICc) |> select(.model:BIC)
## # A tibble: 4 × 6
##   .model   sigma2 log_lik   AIC  AICc   BIC
##   <chr>     <dbl>   <dbl> <dbl> <dbl> <dbl>
## 1 arima011  0.588   -589. 1183. 1183. 1196.
## 2 stepwise  0.588   -589. 1183. 1183. 1196.
## 3 search    0.590   -588. 1188. 1188. 1214.
## 4 arima110  0.660   -618. 1243. 1243. 1260.
#the AICs for both models are pretty large. 


#Setting up the data to have a test and train sample with 80%/20% 
split_index <- floor(0.8 * nrow(mcpi)) 
train <- mcpi[1:split_index, ] 
test <- mcpi[(split_index + 1):nrow(mcpi), ] 

autoplot(train)
## Plot variable not specified, automatically selected `.vars = value`

#The ARIMA model gives Model: (0,1,1)(1,0,0)[12], this AIC is slightly smaller than the ones I used. The model parameters selected were different from my manual selection. I selected the (1,1,0).

fit <- train|>
  model(ARIMA(value))
report(fit)
## Series: value 
## Model: ARIMA(0,1,1)(1,0,0)[12] 
## 
## Coefficients:
##           ma1     sar1
##       -0.7664  -0.1035
## s.e.   0.0296   0.0501
## 
## sigma^2 estimated as 0.5416:  log likelihood=-453.35
## AIC=912.7   AICc=912.75   BIC=924.73
#The AIC for the model is pretty small compared to the results from my manual selection of the parameters. The coefficients for AR1 shows the correlation with the prior time, which is pretty strong at .85. The MA1 shows that theres a negative relationship with the prior time periods shocks. 

fit |>
  gg_tsresiduals()

##plot shows it is acting as white noise. 

fc<- fit |> forecast(h=nrow(test)) 

fc |>
  autoplot(train) +
  labs(y = "Median CPI", title = "Median CPI")

acc <- accuracy(object = fc, test ) |>
  select(.model, ME, MPE, RMSE, MAE, MAPE ) 

library(kableExtra) # Print with knitr::kable 

kable(acc, caption = "Forecast Accuracy Metrics") |> 
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), 
                full_width = FALSE)
Forecast Accuracy Metrics
.model ME MPE RMSE MAE MAPE
ARIMA(value) 1.129489 16.17006 1.997608 1.400813 32.6086
#The mean error is pretty small here at -1, which means the model is a pretty good fit.