Time Series Analysis — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Time Series Analysis (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Time series work fails in two characteristic ways: validating on a random split (which leaks the future into training and produces accuracy numbers that evaporate in production), and shipping a model that never had to beat the dumbest possible baseline. The discipline below exists to prevent both - every forecast is backtested in time order and compared against seasonal-naive before anyone sees it.
Order matters: exploration decides the seasonal period, the period decides the decomposition and model structure, and validation only means something after the model choices are frozen.
series.asfreq("D")); missing timestamps must become explicit NaNs, then be imputed or modeled, never silently skipped.from statsmodels.tsa.seasonal import STL
result = STL(series, period=12).fit()
result.plot()Read the components: if the seasonal panel's amplitude dwarfs the residual panel, seasonality is real; if the residual still shows structure, the period is wrong or a second cycle exists.
from statsmodels.tsa.stattools import adfuller
stat, pvalue, *_ = adfuller(series.dropna())p < 0.05 rejects the unit root - treat the series as stationary. Otherwise difference.
Difference once for trend, seasonally difference for seasonality:
diff = series.diff().dropna()
seasonal_diff = series.diff(12).dropna()Almost never difference more than twice total (d + D ≤ 2); over-differencing injects noise and shows up as a strongly negative lag-1 ACF. Read ACF/PACF on the differenced series to choose orders: PACF cutting off after lag p suggests AR(p); ACF cutting off after lag q suggests MA(q).
SARIMA:
from statsmodels.tsa.statespace.sarimax import SARIMAX
model = SARIMAX(series, order=(1, 1, 1), seasonal_order=(1, 1, 1, 12))
fit = model.fit(disp=False)
forecast = fit.get_forecast(steps=12)
ci = forecast.conf_int()pmdarima.auto_arima can search orders by AIC, but treat its winner as a candidate, not an answer - verify residuals (Step 6) before trusting it.
Prophet, for business series with strong multiple seasonality and holiday effects:
from prophet import Prophet
m = Prophet(yearly_seasonality=True, weekly_seasonality=True)
m.add_country_holidays(country_name="US")
m.fit(df) # columns: ds, y
fc = m.predict(m.make_future_dataframe(periods=90))Apply a log transform first when seasonal amplitude scales with the level (multiplicative seasonality), for either model family.
Backtest with rolling or expanding windows that respect time:
from sklearn.model_selection import TimeSeriesSplit
tscv = TimeSeriesSplit(n_splits=5)Report MAPE, MAE, and RMSE on held-out future windows only - in-sample fit is not evidence. Always fit the seasonal-naive baseline (predict the value from one season ago) through the same backtest. The acceptance threshold: the model's error must beat seasonal-naive (MASE < 1, or lower MAPE on the same folds). A sophisticated model that loses to naive ships the naive.
Residuals from a correct model are white noise:
Always show the confidence interval, and say plainly that uncertainty grows with horizon. Report the backtest error at the actual decision horizon (the 6-month-ahead MAPE for a 6-month decision), not the flattering 1-step-ahead number.
Monthly revenue, 36 points, clear December spike, variance growing with level. Decision trail: period = 12 (monthly with annual cycle, 3 full cycles available - enough). Log transform (multiplicative seasonality). ADF on log series p = 0.41 → difference; on differenced series p = 0.01 → proceed with d = 1, D = 1. ACF/PACF suggest (1,1,1)(0,1,1,12). Backtest on 5 expanding folds at horizon 6: SARIMA MAPE 7.2% vs seasonal-naive 11.8% - model earns its keep, ship with intervals from the log-scale fit back-transformed.
Produce a forecast package containing: the decomposition plot with a one-line reading, the stationarity and transform decisions with test p-values, the chosen model and orders with the rejected candidates named, backtest error (MAPE/MAE/RMSE) at the decision horizon side-by-side with seasonal-naive, residual diagnostics (Ljung-Box p-value, residual ACF), and the forecast with confidence intervals.
Ship only when: the seasonal period is verified by decomposition, not assumed; all accuracy numbers come from time-ordered held-out windows at the decision horizon; the model beats seasonal-naive; Ljung-Box shows no residual autocorrelation; intervals accompany every point forecast; and every data gap, transform, and intervention is documented.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.