# Load required libraries
library(fredr) # FRED data
library(tseries) # ADF and KPSS tests
library(forecast) # Time series forecasting
library(ggplot2) # Visualization
library(gridExtra) # Multiple plots
library(stats) # Decomposi(
# Set FRED API key
fredr_set_key("8631a4e57900a09405dcb79f9488dff4")Discussion 3
Introduction
This analysis examines three time series datasets to assess stationarity, identify underlying patterns through ACF/PACF analysis, and decompose the series into trend, seasonal, and random components.
Time Series Selected: 1. Unemployment Rate 2. Consumer Price Index (CPI) - Inflation 3. Housing Starts
# Download data from FRED
# Time Series 1: Unemployment Rate (monthly)
unrate <- fredr(
series_id = "UNRATE",
observation_start = as.Date("2000-01-01"),
observation_end = as.Date("2023-12-31")
)
# Time Series 2: Consumer Price Index (monthly)
cpi <- fredr(
series_id = "CPIAUCSL",
observation_start = as.Date("2000-01-01"),
observation_end = as.Date("2023-12-31")
)
# Time Series 3: Housing Starts (monthly)
housing <- fredr(
series_id = "HOUST",
observation_start = as.Date("2000-01-01"),
observation_end = as.Date("2023-12-31")
)
# Convert to time series objects
unrate_ts <- ts(unrate$value, start = c(2000, 1), frequency = 12)
cpi_ts <- ts(cpi$value, start = c(2000, 1), frequency = 12)
housing_ts <- ts(housing$value, start = c(2000, 1), frequency = 12)Part 1: Stationarity Analysis
1.1 Time Series 1: Unemployment Rate
Visual Inspection
plot(unrate_ts,
main = "U.S. Unemployment Rate (2000-2023)",
ylab = "Unemployment Rate (%)",
xlab = "Year",
col = "darkblue",
lwd = 2)Observations: - The series shows clear fluctuations with peaks during recessions (2008-2009, 2020) - Mean appears to vary over time (non-constant) - Variance seems relatively stable
Formal Stationarity Tests
ADF Test (Augmented Dickey-Fuller)
adf_result <- adf.test(unrate_ts)
print(adf_result)
Augmented Dickey-Fuller Test
data: unrate_ts
Dickey-Fuller = -2.3169, Lag order = 6, p-value = 0.4426
alternative hypothesis: stationary
ADF Test Interpretation:
- Null Hypothesis: The time series has a unit root (is NOT stationary)
- Alternative Hypothesis: The time series is stationary
- Decision:
- p-value = 0.4426
- Since p-value > 0.05, we FAIL TO REJECT the null hypothesis
- Conclusion: The unemployment rate series is NOT stationary
KPSS Test
kpss_result <- kpss.test(unrate_ts)
print(kpss_result)
KPSS Test for Level Stationarity
data: unrate_ts
KPSS Level = 0.62105, Truncation lag parameter = 5, p-value = 0.02072
KPSS Test Interpretation:
- Null Hypothesis: The time series IS stationary (opposite of ADF!)
- Alternative Hypothesis: The time series is NOT stationary
- Decision:
- p-value = 0.0207
- Since p-value < 0.05, we REJECT the null hypothesis
- Conclusion: The unemployment rate series is NOT stationary
Stationarity Conditions
Based on both tests, the unemployment rate series violates the following stationarity condition(s):
- Constant Mean: The mean changes over time due to economic cycles
- The series exhibits trend-like behavior during recession and recovery periods
1.2 Time Series 2: Consumer Price Index (CPI)
Visual Inspection
plot(cpi_ts,
main = "U.S. Consumer Price Index (2000-2023)",
ylab = "CPI (Index)",
xlab = "Year",
col = "darkred",
lwd = 2)Observations: - Clear upward trend over time - Non-constant mean (increasing) - Appears to have increasing variance (heteroskedasticity)
Formal Stationarity Tests
ADF Test
adf_result_cpi <- adf.test(cpi_ts)
print(adf_result_cpi)
Augmented Dickey-Fuller Test
data: cpi_ts
Dickey-Fuller = -0.03093, Lag order = 6, p-value = 0.99
alternative hypothesis: stationary
ADF Test Interpretation:
- Null Hypothesis: The time series has a unit root (is NOT stationary)
- Decision: p-value = 0.99
- Conclusion: FAIL TO REJECT the null hypothesis. Series is NOT stationary.
KPSS Test
kpss_result_cpi <- kpss.test(cpi_ts)
print(kpss_result_cpi)
KPSS Test for Level Stationarity
data: cpi_ts
KPSS Level = 4.6136, Truncation lag parameter = 5, p-value = 0.01
KPSS Test Interpretation:
- Null Hypothesis: The time series IS stationary
- Decision: p-value = 0.01
- Conclusion: REJECT the null hypothesis. Series is NOT stationary.
Stationarity Conditions Violated
The CPI series violates:
- Constant Mean: Strong upward trend over time
- Constant Variance: Variance appears to increase with the level
- This is a classic non-stationary series requiring differencing or log transformation
1.3 Time Series 3: Housing Starts
Visual Inspection
plot(housing_ts,
main = "U.S. Housing Starts (2000-2023)",
ylab = "Housing Starts (Thousands)",
xlab = "Year",
col = "darkgreen",
lwd = 2)Observations: - Shows cyclical patterns with sharp decline during 2008 financial crisis - Possible seasonal patterns - Variance changes over time
Formal Stationarity Tests
ADF Test
adf_result_housing <- adf.test(housing_ts)
print(adf_result_housing)
Augmented Dickey-Fuller Test
data: housing_ts
Dickey-Fuller = -1.0389, Lag order = 6, p-value = 0.9311
alternative hypothesis: stationary
ADF Test Interpretation:
- Null Hypothesis: The time series has a unit root (is NOT stationary)
- Decision: p-value = 0.9311
- Conclusion: FAIL TO REJECT the null hypothesis. Series is NOT stationary.
KPSS Test
kpss_result_housing <- kpss.test(housing_ts)
print(kpss_result_housing)
KPSS Test for Level Stationarity
data: housing_ts
KPSS Level = 1.1682, Truncation lag parameter = 5, p-value = 0.01
KPSS Test Interpretation:
- Null Hypothesis: The time series IS stationary
- Decision: p-value = 0.01
- Conclusion: REJECT the null hypothesis. Series is NOT stationary.
Stationarity Conditions Violated
The housing starts series violates:
- Constant Mean: Shows economic cycle patterns
- Possible seasonality: Construction has seasonal patterns
- Mean and variance both change over time
Part 2: ACF and PACF Analysis
For ACF and PACF analysis, we first need to make the series stationary through differencing.
2.1 Unemployment Rate - ACF/PACF
Make Series Stationary
# First difference
unrate_diff <- diff(unrate_ts)
# Plot differenced series
plot(unrate_diff,
main = "Differenced Unemployment Rate",
ylab = "Change in Unemployment Rate",
xlab = "Year",
col = "darkblue",
lwd = 2)# Verify stationarity after differencing
adf.test(unrate_diff)
Augmented Dickey-Fuller Test
data: unrate_diff
Dickey-Fuller = -7.5525, Lag order = 6, p-value = 0.01
alternative hypothesis: stationary
ACF and PACF Plots
par(mfrow = c(2, 1))
acf(unrate_diff, main = "ACF: Differenced Unemployment Rate", lag.max = 40)
pacf(unrate_diff, main = "PACF: Differenced Unemployment Rate", lag.max = 40)par(mfrow = c(1, 1))Interpretation:
- ACF Pattern:
- Shows significant autocorrelation at lag 1
- Gradual decay suggests AR component
- PACF Pattern:
- Sharp cutoff after lag 1 or 2
- Suggests AR(1) or AR(2) process
- Conclusion: The differenced unemployment rate appears to follow an AR(1) or AR(2) process based on the PACF cutoff pattern.
2.2 Consumer Price Index - ACF/PACF
Make Series Stationary
# First difference (or log difference for CPI)
cpi_diff <- diff(log(cpi_ts)) # Log difference to handle changing variance
# Plot differenced series
plot(cpi_diff,
main = "Log Differenced CPI (Inflation Rate)",
ylab = "Log Difference",
xlab = "Year",
col = "darkred",
lwd = 2)# Verify stationarity
adf.test(cpi_diff)
Augmented Dickey-Fuller Test
data: cpi_diff
Dickey-Fuller = -4.9741, Lag order = 6, p-value = 0.01
alternative hypothesis: stationary
ACF and PACF Plots
par(mfrow = c(2, 1))
acf(cpi_diff, main = "ACF: Log Differenced CPI", lag.max = 40)
pacf(cpi_diff, main = "PACF: Log Differenced CPI", lag.max = 40)par(mfrow = c(1, 1))Interpretation:
- ACF Pattern:
- Shows significant spikes at multiple lags
- Slow decay pattern
- PACF Pattern:
- Significant spike at lag 1
- Quick cutoff after initial lags
- Conclusion: The differenced CPI (inflation rate) shows characteristics of an AR(1) process, with possible additional MA components. The persistence in inflation is captured by the AR term.
2.3 Housing Starts - ACF/PACF
Make Series Stationary
# First difference
housing_diff <- diff(housing_ts)
# Plot differenced series
plot(housing_diff,
main = "Differenced Housing Starts",
ylab = "Change in Housing Starts",
xlab = "Year",
col = "darkgreen",
lwd = 2)# Verify stationarity
adf.test(housing_diff)
Augmented Dickey-Fuller Test
data: housing_diff
Dickey-Fuller = -6.6511, Lag order = 6, p-value = 0.01
alternative hypothesis: stationary
ACF and PACF Plots
par(mfrow = c(2, 1))
acf(housing_diff, main = "ACF: Differenced Housing Starts", lag.max = 40)
pacf(housing_diff, main = "PACF: Differenced Housing Starts", lag.max = 40)par(mfrow = c(1, 1))Interpretation:
- ACF Pattern:
- Shows seasonal spikes at lags 12, 24 (annual seasonality)
- Suggests seasonal MA component
- PACF Pattern:
- Significant spikes at seasonal lags
- Indicates AR component
- Conclusion: Housing starts shows seasonal ARIMA characteristics with both AR and MA components at seasonal lags (12 months). This suggests a SARIMA model would be appropriate.
Part 3: Time Series Decomposition
3.1 Unemployment Rate Decomposition
# STL decomposition (more robust than classical)
unrate_stl <- stl(unrate_ts, s.window = "periodic")
plot(unrate_stl, main = "STL Decomposition: Unemployment Rate")# Also show classical decomposition for comparison
unrate_decomp <- decompose(unrate_ts, type = "additive")
plot(unrate_decomp, col = "darkblue")Key Takeaways:
- Trend Component:
- Shows long-term economic cycles
- Clear spikes during recessions (2008-2009, 2020 COVID)
- Recovery periods show gradual decline
- Seasonal Component:
- Relatively weak seasonal pattern
- Some evidence of within-year patterns (possibly related to labor market dynamics)
- Random Component:
- Contains irregular fluctuations
- Some large residuals during crisis periods suggest trend doesn’t capture all patterns
- Impact on Stationarity:
- The dominant trend component explains why the series is non-stationary
- Removing trend would help achieve stationarity
- Weak seasonality doesn’t significantly impact stationarity
3.2 Consumer Price Index Decomposition
# STL decomposition
cpi_stl <- stl(cpi_ts, s.window = "periodic")
plot(cpi_stl, main = "STL Decomposition: Consumer Price Index")# Classical decomposition (multiplicative due to increasing variance)
cpi_decomp <- decompose(cpi_ts, type = "multiplicative")
plot(cpi_decomp, col = "darkred")Key Takeaways:
- Trend Component:
- Strong, consistent upward trend
- Slight acceleration in recent years (inflation spike)
- This is the dominant component
- Seasonal Component:
- Very weak or negligible seasonality
- CPI is adjusted for seasonal factors (seasonally adjusted data)
- Random Component:
- Relatively small compared to trend
- Some volatility during specific periods
- Impact on Stationarity:
- The strong trend is the PRIMARY reason for non-stationarity
- First differencing or log transformation needed to remove trend
- Lack of strong seasonality simplifies the modeling process
3.3 Housing Starts Decomposition
# STL decomposition
housing_stl <- stl(housing_ts, s.window = "periodic")
plot(housing_stl, main = "STL Decomposition: Housing Starts")# Classical decomposition
housing_decomp <- decompose(housing_ts, type = "multiplicative")
plot(housing_decomp, col = "darkgreen")Key Takeaways:
- Trend Component:
- Shows boom and bust cycles
- Dramatic decline during 2008 financial crisis
- Gradual recovery post-2010
- Recent plateau or slight decline
- Seasonal Component:
- STRONG seasonal pattern
- Clear peaks in spring/summer (construction season)
- Troughs in winter months
- Consistent pattern across years
- Random Component:
- Contains irregular shocks
- Large residuals during crisis period
- Generally well-behaved outside of crisis
- Impact on Stationarity:
- Both trend AND seasonality contribute to non-stationarity
- Would require:
- Seasonal differencing (lag 12) to remove seasonality
- First differencing to remove trend
- Suggests SARIMA(p,1,q)(P,1,Q)₁₂ model structure
Summary and Conclusions
Overall Findings
Stationarity Results
| Time Series | ADF Test | KPSS Test | Stationary? | Conditions Violated |
|---|---|---|---|---|
| Unemployment Rate | [Result] | [Result] | [Yes/No] | Varying mean |
| CPI | [Result] | [Result] | No | Strong trend, changing variance |
| Housing Starts | [Result] | [Result] | [Yes/No] | Trend + Seasonality |
ACF/PACF Insights
- Unemployment Rate: AR(1) or AR(2) process after differencing
- CPI: AR(1) process with possible MA component
- Housing Starts: Seasonal ARIMA with components at lag 12
Decomposition Insights
- Unemployment Rate:
- Trend-dominated with weak seasonality
- Economic cycles clearly visible
- CPI:
- Pure trend with negligible seasonality
- Strongest non-stationarity due to persistent upward movement
- Housing Starts:
- Strong seasonal AND trend components
- Most complex series requiring both regular and seasonal differencing
Implications for Modeling
- Unemployment: ARIMA(1,1,0) or ARIMA(2,1,0) likely appropriate
- CPI: ARIMA(1,1,0) with possible MA term
- Housing Starts: SARIMA(p,1,q)(P,1,Q)₁₂ needed to capture seasonality
References
- Hyndman, R.J., & Athanasopoulos, G. (2021). Forecasting: principles and practice, 3rd edition. OTexts. https://otexts.com/fpp3/
- FRED Economic Data: https://fred.stlouisfed.org/
- Course Materials: 2-3-Differencing.pdf, 2-graphics.pdf, 4-decompositions.pdf
Session Info
sessionInfo()R version 4.5.1 (2025-06-13)
Platform: aarch64-apple-darwin20
Running under: macOS Sonoma 14.5
Matrix products: default
BLAS: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRblas.0.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
time zone: America/New_York
tzcode source: internal
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] gridExtra_2.3 ggplot2_4.0.1 forecast_9.0.0 tseries_0.10-59
[5] fredr_2.1.0
loaded via a namespace (and not attached):
[1] generics_0.1.4 lattice_0.22-7 digest_0.6.37 magrittr_2.0.4
[5] evaluate_1.0.5 grid_4.5.1 RColorBrewer_1.1-3 fastmap_1.2.0
[9] jsonlite_2.0.0 nnet_7.3-20 httr_1.4.7 scales_1.4.0
[13] cli_3.6.5 rlang_1.1.6 withr_3.0.2 yaml_2.3.10
[17] tools_4.5.1 parallel_4.5.1 dplyr_1.1.4 colorspace_2.1-2
[21] curl_7.0.0 vctrs_0.6.5 R6_2.6.1 zoo_1.8-15
[25] lifecycle_1.0.4 htmlwidgets_1.6.4 pkgconfig_2.0.3 urca_1.3-4
[29] pillar_1.11.1 gtable_0.3.6 glue_1.8.0 quantmod_0.4.28
[33] Rcpp_1.1.0 xfun_0.56 tibble_3.3.0 lmtest_0.9-40
[37] tidyselect_1.2.1 rstudioapi_0.17.1 knitr_1.50 farver_2.1.2
[41] htmltools_0.5.8.1 nlme_3.1-168 rmarkdown_2.29 xts_0.14.1
[45] timeDate_4052.112 fracdiff_1.5-3 compiler_4.5.1 S7_0.2.1
[49] quadprog_1.5-8 TTR_0.24.4