Skip to main content Skills Marktplatz Entdecken und erkunden Sie KI-Skills, die von der Community erstellt wurden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Prompt kopierenPrompt-Details anzeigen Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
npx skills add https://github.com/wookat/ai-research-skills --skill time-series-analysisDer Befehl bleibt in einer Zeile. Scrollen Sie horizontal, um ihn vor dem Kopieren vollständig zu prüfen.
Sie bevorzugen eine lokale Kopie? Laden Sie die Dateien herunter, die SkillsMP derzeit vorliegen.
ZIP herunterladen Herunterladen... Mehr aus diesem Repository
Search papers across arXiv, DBLP, OpenAlex, OpenReview, Semantic Scholar, and Crossref for a given query and year range, using ./scripts/search_papers.py. Use when the user asks to find papers, related work, prior art, or recent publications on a specific topic, especially when they mention a date range or specific venues like NeurIPS, ICLR, or ICML.
Verwandte Berufe SOC
Basierend auf der SOC-Berufsklassifikation
name time-series-analysis description Use this Skill for time series analysis: ARIMA/SARIMA identification (ACF/PACF, AIC), seasonal decomposition (STL), VAR, GARCH volatility, and forecast evaluation.
tags ["mathematics","time-series","ARIMA","VAR","GARCH","forecasting"] version 1.0.0 authors [{"name":"awesome-rosetta-skills contributors","github":"@xjtulyc"}] license MIT platforms ["claude-code","codex","gemini-cli","cursor"] dependencies {"python":["statsmodels>=0.14","pmdarima>=2.0","arch>=6.0","pandas>=1.5","matplotlib>=3.6","scipy>=1.9"]} last_updated 2026-03-17 status stable
Time Series Analysis
TL;DR — Full pipeline from stationarity testing and ACF/PACF identification
through ARIMA/SARIMA fitting, STL decomposition, VAR impulse response, GARCH
volatility modelling, and rigorous forecast evaluation (MASE, DM test).
When to Use
Use this Skill when you need to:
Determine the order of an ARIMA model from ADF / KPSS tests and ACF/PACF plots.
Fit and forecast with ARIMA, SARIMA, or auto-ARIMA (pmdarima).
Decompose a seasonal series into trend, seasonal, and residual components via STL.
Model multivariate dynamics with a Vector Autoregression (VAR).
Estimate conditional volatility clustering with GARCH(1,1).
Compare forecasts rigorously using Diebold-Mariano (DM) test and CRPS.
Task Tool Univariate forecasting statsmodels ARIMA / pmdarima auto_arimaSeasonal decomposition statsmodels STLMultivariate forecasting statsmodels VARVolatility modelling arch GARCHModel selection AIC, BIC, out-of-sample MASE
Background & Key Concepts
Stationarity
A time series is weakly stationary if its mean and autocovariance structure do not
change over time. Most classical methods require stationarity:
Apply first-differencing (d=1) to remove stochastic trends.
Apply seasonal differencing (D=1 at lag s) to remove seasonal unit roots.
Confirm with ADF (null: unit root, want rejection) and KPSS (null: stationary,
want non-rejection).
ARIMA(p, d, q)
p AR lags identified from PACF cutting off after lag p.
d differencing order from unit-root tests.
q MA lags identified from ACF cutting off after lag q.
Seasonal extension: SARIMA(p,d,q)(P,D,Q)[s].
VAR(p)
A system of k variables, each regressed on p lags of all k variables.
Lag order p chosen by AIC/BIC. Impulse response functions (IRF) trace the dynamic
effect of a one-unit shock to variable j on all other variables over h horizons.
GARCH(1,1) Conditional variance: h_t = omega + alpha * e_{t-1}^2 + beta * h_{t-1}.
alpha + beta < 1 ensures covariance stationarity.
News impact curve: how a return shock of size e affects next-period variance.
Environment Setup conda create -n ts python=3.11 -y
conda activate ts
pip install statsmodels>=0.14 pmdarima>=2.0 arch >=6.0 \
pandas>=1.5 matplotlib>=3.6 scipy>=1.9
python -c "import statsmodels, pmdarima, arch; print('OK')"
Core Workflow
Step 1 — Stationarity Tests import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller, kpss
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
np.random.seed(42 )
n = 300
t = np.arange(n)
series = 0.05 * t + np.random.randn(n).cumsum() * 0.5
ts = pd.Series(series, index=pd.date_range("2010-01-01" , periods=n, freq="W" ))
def run_stationarity_tests (x: pd.Series, label: str = "series" ) -> dict :
"""
Run ADF and KPSS stationarity tests and return a summary dict.
ADF H0: unit root present (reject -> stationary)
KPSS H0: series is stationary (reject -> non-stationary)
"""
adf_stat, adf_p, adf_lags, _, adf_cv, _ = adfuller(x, autolag="AIC" )
kpss_stat, kpss_p, kpss_lags, kpss_cv = kpss(x, regression="c" , nlags="auto" )
result = {
"label" : label,
"adf_stat" : adf_stat,
"adf_p" : adf_p,
"kpss_stat" : kpss_stat,
"kpss_p" : kpss_p,
"adf_cv_5pct" : adf_cv["5%" ],
"kpss_cv_5pct" : kpss_cv["5%" ],
"likely_stationary" : (adf_p < 0.05 ) and (kpss_p > 0.05 ),
}
print (f"[{label} ] ADF stat={adf_stat:.3 f} p={adf_p:.4 f} "
f"(5% cv={adf_cv['5%' ]:.3 f} )" )
print (f"[{label} ] KPSS stat={kpss_stat:.3 f} p={kpss_p:.4 f} "
f"(5% cv={kpss_cv['5%' ]:.3 f} )" )
print (f"[{label} ] Likely stationary: {result['likely_stationary' ]} " )
return result
print ("=== Level series ===" )
r0 = run_stationarity_tests(ts, "levels" )
ts_diff = ts.diff().dropna()
print ("\n=== First difference ===" )
r1 = run_stationarity_tests(ts_diff, "first_diff" )
fig, axes = plt.subplots(2 , 2 , figsize=(12 , 6 ))
plot_acf(ts, lags=30 , ax=axes[0 , 0 ], title="ACF — Levels" )
plot_pacf(ts, lags=30 , ax=axes[0 , 1 ], title="PACF — Levels" )
plot_acf(ts_diff, lags=30 , ax=axes[1 , 0 ], title="ACF — First Diff" )
plot_pacf(ts_diff,lags=30 , ax=axes[1 , 1 ], title="PACF — First Diff" )
fig.tight_layout()
fig.savefig("acf_pacf.png" , dpi=150 )
print ("\nSaved acf_pacf.png" )
Step 2 — ARIMA Identification and Forecast import warnings
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.statespace.sarimax import SARIMAX
import pmdarima as pm
np.random.seed(0 )
from statsmodels.tsa.arima_process import ArmaProcess
ar_coefs = np.array([1 , -0.6 , -0.3 ])
ma_coefs = np.array([1 , 0.4 ])
arma_process = ArmaProcess(ar_coefs, ma_coefs)
data_stationary = arma_process.generate_sample(nsample=400 )
data_nonstationary = np.cumsum(data_stationary)
dates = pd.date_range("2010-01-01" , periods=len (data_nonstationary), freq="M" )
ys = pd.Series(data_nonstationary, index=dates)
train, test = ys[:-24 ], ys[-24 :]
with warnings.catch_warnings():
warnings.simplefilter("ignore" )
manual_model = ARIMA(train, order=(2 , 1 , 1 ))
manual_fit = manual_model.fit()
print (manual_fit.summary())
forecast = manual_fit.get_forecast(steps=24 )
fc_mean = forecast.predicted_mean
fc_ci = forecast.conf_int(alpha=0.05 )
fig, ax = plt.subplots(figsize=(10 , 4 ))
ax.plot(train[-48 :], label="Train (last 48)" )
ax.plot(test, label="Actual test" , color="black" )
ax.plot(fc_mean, label="ARIMA(2,1,1) forecast" , color="red" )
ax.fill_between(fc_ci.index, fc_ci.iloc[:, 0 ], fc_ci.iloc[:, 1 ],
alpha=0.2 , color="red" , label="95% CI" )
ax.legend()
ax.set_title("ARIMA(2,1,1) Forecast" )
fig.tight_layout()
fig.savefig("arima_forecast.png" , dpi=150 )
print ("\nRunning auto_arima..." )
auto_model = pm.auto_arima(
train,
d=1 ,
start_p=0 , max_p=4 ,
start_q=0 , max_q=4 ,
seasonal=False ,
information_criterion="aic" ,
stepwise=True ,
trace=True ,
error_action="ignore" ,
suppress_warnings=True ,
)
print (f"\nBest auto_arima order: {auto_model.order} " )
auto_fc, auto_ci = auto_model.predict(n_periods=24 , return_conf_int=True )
auto_fc_series = pd.Series(auto_fc, index=test.index)
def mase (actual: np.ndarray, forecast: np.ndarray, insample: np.ndarray ) -> float :
"""Mean Absolute Scaled Error (scale-free, handles zeros)."""
naive_mae = np.mean(np.abs (np.diff(insample)))
mae = np.mean(np.abs (actual - forecast))
return mae / naive_mae if naive_mae > 0 else np.inf
def mape (actual: np.ndarray, forecast: np.ndarray ) -> float :
"""Mean Absolute Percentage Error."""
mask = actual != 0
return np.mean(np.abs ((actual[mask] - forecast[mask]) / actual[mask])) * 100
manual_mase = mase(test.values, fc_mean.values, train.values)
auto_mase = mase(test.values, auto_fc, train.values)
print (f"\nManual ARIMA(2,1,1) MASE: {manual_mase:.4 f} " )
print (f"Auto ARIMA {auto_model.order} MASE: {auto_mase:.4 f} " )
Step 3 — STL Decomposition and VAR from statsmodels.tsa.seasonal import STL
from statsmodels.tsa.vector_ar.var_model import VAR
n = 120
t = np.arange(n)
seasonal_component = 3 * np.sin(2 * np.pi * t / 12 )
trend_component = 0.1 * t
noise = np.random.randn(n) * 0.5
y_seasonal = pd.Series(
trend_component + seasonal_component + noise,
index=pd.date_range("2014-01-01" , periods=n, freq="ME" ),
)
stl = STL(y_seasonal, period=12 , robust=True )
stl_result = stl.fit()
fig = stl_result.plot()
fig.set_size_inches(10 , 7 )
fig.suptitle("STL Decomposition" , y=1.01 )
fig.tight_layout()
fig.savefig("stl_decomposition.png" , dpi=150 )
print ("Saved stl_decomposition.png" )
rem = stl_result.resid
seas = stl_result.seasonal
seasonal_strength = max (0 , 1 - np.var(rem) / np.var(seas + rem))
print (f"Seasonal strength: {seasonal_strength:.4 f} " )
np.random.seed(1 )
n_var = 200
B = np.array([[0.7 , -0.2 ], [0.1 , 0.8 ]])
eps = np.random.multivariate_normal([0 , 0 ], [[1 , 0.3 ], [0.3 , 1 ]], n_var)
Y = np.zeros((n_var, 2 ))
for t_ in range (1 , n_var):
Y[t_] = B @ Y[t_-1 ] + eps[t_]
df_var = pd.DataFrame(Y, columns=["y1" , "y2" ],
index=pd.date_range("2005-01" , periods=n_var, freq="ME" ))
model_var = VAR(df_var)
lag_result = model_var.select_order(maxlags=8 )
print ("\nVAR lag selection:" )
print (lag_result.summary())
best_lag = lag_result.aic
var_fit = model_var.fit(best_lag)
print (var_fit.summary())
gc_test = var_fit.test_causality("y1" , "y2" , kind="f" )
print (f"\nGranger causality y2 -> y1: F={gc_test.test_statistic:.4 f} , p={gc_test.pvalue:.4 f} " )
irf = var_fit.irf(periods=12 )
fig_irf = irf.plot(orth=True )
fig_irf.set_size_inches(8 , 5 )
fig_irf.tight_layout()
fig_irf.savefig("var_irf.png" , dpi=150 )
print ("Saved var_irf.png" )
var_fc = var_fit.forecast(df_var.values[-best_lag:], steps=12 )
print ("\nVAR 12-step forecast (first 3 rows):" )
print (pd.DataFrame(var_fc[:3 ], columns=["y1_hat" , "y2_hat" ]))
Advanced Usage
GARCH(1,1) Volatility Modelling from arch import arch_model
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(42 )
n_garch = 1000
omega, alpha, beta = 0.0001 , 0.1 , 0.85
h = np.zeros(n_garch)
r = np.zeros(n_garch)
h[0 ] = omega / (1 - alpha - beta)
for t in range (1 , n_garch):
h[t] = omega + alpha * r[t-1 ]**2 + beta * h[t-1 ]
r[t] = np.sqrt(h[t]) * np.random.randn()
returns = pd.Series(r * 100 , name="returns" )
garch_model = arch_model(returns, vol="Garch" , p=1 , q=1 , dist="normal" , mean="Zero" )
garch_fit = garch_model.fit(disp="off" )
print (garch_fit.summary())
params = garch_fit.params
print (f"\nEstimated omega={params['omega' ]:.6 f} alpha={params['alpha[1]' ]:.4 f} "
f"beta={params['beta[1]' ]:.4 f} " )
print (f"alpha + beta = {params['alpha[1]' ] + params['beta[1]' ]:.4 f} "
f"(< 1 -> covariance stationary)" )
cond_vol = garch_fit.conditional_volatility
fig, axes = plt.subplots(2 , 1 , figsize=(10 , 6 ), sharex=True )
axes[0 ].plot(returns, color="grey" , linewidth=0.5 , label="Returns" )
axes[0 ].set_title("Returns" )
axes[1 ].plot(cond_vol, color="darkred" , linewidth=0.8 , label="Conditional vol" )
axes[1 ].set_title("GARCH(1,1) Conditional Volatility" )
for ax in axes:
ax.legend(loc="upper right" )
fig.tight_layout()
fig.savefig("garch_volatility.png" , dpi=150 )
print ("Saved garch_volatility.png" )
garch_fc = garch_fit.forecast(horizon=10 , reindex=False )
vol_fc = np.sqrt(garch_fc.variance.iloc[-1 ])
print ("\n10-step ahead conditional std deviation forecast:" )
print (vol_fc.values.round (4 ))
Diebold-Mariano Forecast Comparison Test from scipy.stats import t as t_dist
import numpy as np
def diebold_mariano_test (
actual: np.ndarray,
forecast1: np.ndarray,
forecast2: np.ndarray,
h: int = 1 ,
loss: str = "mse" ,
) -> dict :
"""
Diebold-Mariano test for equal predictive accuracy.
H0: E[d_t] = 0 (equal forecast accuracy)
H1: model 1 is more accurate (one-sided) or different (two-sided)
Args:
actual: Array of true values.
forecast1: Array of model 1 predictions.
forecast2: Array of model 2 predictions.
h: Forecast horizon (>1 needs Newey-West HAC).
loss: 'mse' or 'mae'.
Returns:
dict with DM statistic, p-value, and conclusion.
"""
e1 = actual - forecast1
e2 = actual - forecast2
if loss == "mse" :
d = e1**2 - e2**2
elif loss == "mae" :
d = np.abs (e1) - np.abs (e2)
else :
raise ValueError("loss must be 'mse' or 'mae'" )
n = len (d)
d_bar = np.mean(d)
gamma0 = np.var(d, ddof=1 )
gamma_sum = sum (
(1 - k / (h + 1 )) * np.cov(d[k:], d[:-k])[0 , 1 ]
for k in range (1 , h)
) if h > 1 else 0.0
var_d = (gamma0 + 2 * gamma_sum) / n
se_d = np.sqrt(max (var_d, 1e-12 ))
dm_stat = d_bar / se_d
p_value = 2 * t_dist.sf(abs (dm_stat), df=n - 1 )
return {
"dm_statistic" : float (dm_stat),
"p_value" : float (p_value),
"mean_diff" : float (d_bar),
"conclusion" : "Model 1 better" if dm_stat < 0 else "Model 2 better"
if p_value < 0.05 else "No significant difference" ,
}
np.random.seed(10 )
y_true = np.random.randn(100 )
fc1 = y_true + np.random.randn(100 ) * 0.8
fc2 = y_true + np.random.randn(100 ) * 1.2
dm = diebold_mariano_test(y_true, fc1, fc2, h=1 , loss="mse" )
print (f"DM statistic : {dm['dm_statistic' ]:.4 f} " )
print (f"p-value : {dm['p_value' ]:.4 f} " )
print (f"Conclusion : {dm['conclusion' ]} " )
Troubleshooting Error / Symptom Cause Fix MLE Optimization Failed to ConvergePoor starting values Set start_params manually; try different method (e.g., 'powell') ARIMA ACF of residuals shows autocorrelationUnder-specified model Increase p or q; check Ljung-Box test on residuals KPSS LevelWarning: p-value is outside look-up tableExtreme test statistic Series is strongly non-stationary; apply differencing VAR: LinAlgError: Singular matrix Collinear variables Drop one collinear variable or apply first difference GARCH: alpha + beta >= 1 Near-integrated volatility Use IGARCH or constrain parameters: constraints={'type':'ineq','fun': lambda p: 0.999 - p[1] - p[2]} pmdarima auto_arima very slowStepwise=False searches all combos Set stepwise=True; reduce max_p, max_q
External Resources
Changelog Version Date Change 1.0.0 2026-03-17 Initial release — ARIMA, SARIMA, STL, VAR, GARCH, DM test