Time Series Analysis & Forecasting ✦

Data Science Interview Notes β€” components, stationarity, ACF/PACF, ARIMA family, CV

Big idea: time series data breaks the i.i.d. assumption most ML relies on β€” order matters, and today depends on yesterday. Almost every interview question here is really asking: "do you understand why time makes this different from tabular ML?"


1. Components of a Time Series

Additive vs Multiplicative decomposition

ModelFormulaWhen to use
AdditiveY = T + S + C + RSeasonal fluctuation size stays constant over time, regardless of trend level
MultiplicativeY = T Γ— S Γ— C Γ— RSeasonal fluctuation grows/shrinks proportionally with the trend (e.g., sales seasonality swings get bigger as overall sales grow)
Quick visual test: plot the series. If the seasonal "wiggle" height stays the same throughout β†’ additive. If the wiggles get bigger as the series grows β†’ multiplicative. (Or take log(Y) to convert multiplicative β†’ additive β€” very common interview trick.)

2. Stationarity

Why models need it

Augmented Dickey-Fuller (ADF) Test

Making a series stationary

"How many times did you difference?" β†’ that count is the d in ARIMA(p,d,q). Most real series need d=0 or d=1, rarely d=2 (over-differencing adds noise and creates its own artificial autocorrelation).

Code β€” ADF test with statsmodels

from statsmodels.tsa.stattools import adfuller

result = adfuller(series.dropna())

print("ADF Statistic:", result[0])
print("p-value:", result[1])
print("Critical Values:", result[4])

# decision rule
if result[1] <= 0.05:
    print("Reject H0 -> series is stationary")
else:
    print("Fail to reject H0 -> difference the series and re-test")

3. Autocorrelation β€” ACF & PACF

How to read them to pick p and q

ModelACF patternPACF pattern
AR(p)Tails off gradually (decays slowly/sinusoidally)Cuts off sharply after lag p β†’ number of significant spikes = p
MA(q)Cuts off sharply after lag q β†’ number of significant spikes = qTails off gradually
ARMA(p,q)Tails offTails off

Memory trick: "AR shows up in PACF, MA shows up in ACF." The one that cuts off cleanly tells you that model's order.

In practice today: nobody eyeballs ACF/PACF plots to pick exact (p,q) for production β€” everyone uses auto_arima / grid search over AIC/BIC. But interviewers ask this to check you understand what the search is actually optimizing, so know the manual method cold.

4. Forecasting Algorithms

AR β€” Autoregressive

Y_t = c + φ₁Y_{t-1} + Ο†β‚‚Y_{t-2} + ... + Ο†β‚šY_{t-p} + Ξ΅_t β€” today's value is a linear combination of its own past values. Order p = how many lags back you regress on.

MA β€” Moving Average (model, not the smoothing technique!)

Y_t = ΞΌ + θ₁Ρ_{t-1} + ΞΈβ‚‚Ξ΅_{t-2} + ... + ΞΈ_qΞ΅_{t-q} + Ξ΅_t β€” today's value is a linear combination of past forecast errors, not past values. Order q = how many lagged error terms.

Common trap: "MA model" β‰  "moving average smoothing" (the rolling-mean trend line). Interviewers love this distinction β€” say it explicitly to show you're not confusing the two.

ARIMA(p, d, q)

SARIMA(p,d,q)(P,D,Q,m)

Prophet β€” intuition (Facebook/Meta)

Code β€” ARIMA fit with statsmodels

from statsmodels.tsa.arima.model import ARIMA

# order=(p, d, q) chosen from ACF/PACF or auto_arima / AIC search
model = ARIMA(train_series, order=(2, 1, 1))
fitted = model.fit()

print(fitted.summary())        # check coefficient p-values, AIC/BIC
forecast = fitted.forecast(steps=12)   # forecast next 12 periods

# for seasonal data use SARIMAX instead:
from statsmodels.tsa.statespace.sarimax import SARIMAX
sarima_model = SARIMAX(train_series, order=(1,1,1),
                        seasonal_order=(1,1,1,12))
sarima_fitted = sarima_model.fit()

Decision Flowchart β€” picking (p, d, q)

Raw series
↓
Run ADF test
↓
p-value > 0.05? (non-stationary)
↓ yes
Difference the series (d += 1); check for seasonality β†’ seasonal differencing if needed. Re-run ADF.
↓ repeat until p ≀ 0.05
Stationary series obtained β†’ note total differences taken = d
↓
Plot ACF and PACF on the stationary series
↓
PACF cuts off sharply at lag p, ACF tails off
β†’ pick AR(p) : set p = cutoff lag, q = 0
ACF cuts off sharply at lag q, PACF tails off
β†’ pick MA(q) : set q = cutoff lag, p = 0
Both ACF & PACF tail off gradually
β†’ mixed ARMA(p,q) : start small (e.g., 1,1) and tune
↓
Fit candidate ARIMA(p,d,q) models β†’ compare via AIC/BIC (lower is better) and residual diagnostics (residuals should look like white noise β€” check via Ljung-Box test)
↓
Final model selected

5. Time Series Cross-Validation

Why standard K-Fold CV fails

Rolling-Window / TimeSeriesSplit CV

Train[1:10] β†’ Val[11:12]
β†’
Train[1:12] β†’ Val[13:14]
β†’
Train[1:14] β†’ Val[15:16]
from sklearn.model_selection import TimeSeriesSplit

tscv = TimeSeriesSplit(n_splits=5)
for train_idx, val_idx in tscv.split(series):
    train, val = series[train_idx], series[val_idx]
    # fit on train, evaluate on val, forward-chaining only
One-liner for the interview: "K-Fold assumes i.i.d. samples; time series violates that because of temporal ordering and autocorrelation β€” so we use forward-chaining CV (TimeSeriesSplit) which always validates on data that comes after the training window."

β€” end of notes, good luck! ✦ β€”