Time Series Analysis — Claude Code skill: trends, seasonality
A skill that walks your agent through time series work: decomposition, stationarity checks, ARIMA and forecasts in Python. Useful for sales or traffic data.
npx skills add aj-geddes/useful-ai-prompts --skill time-series-analysis -a claude-codeWhat Time Series Analysis does
The skill covers data collected over time: trend, seasonality, cyclicity, autocorrelation. It ships techniques for decomposition, differencing, ARIMA and SARIMA models, exponential smoothing. Your agent gets runnable Python instead of vague statistics talk.
The examples rely on pandas, numpy, matplotlib and statsmodels. Stationarity is checked with the Augmented Dickey-Fuller test, then ACF and PACF plots guide the model order, and the forecast comes with a confidence interval. Forecast quality is measured with MAE, RMSE and MAPE.
No statsmodels in your environment means the code will not run, so check that before asking for a forecast. A Granger causality test is included for multiple series, wrapped in exception handling because it does not always succeed.
What it helps with
- split a series into trend, seasonal and residual parts
- test stationarity before fitting a model
- pick ARIMA orders from ACF and PACF plots
- produce a forecast with a confidence interval
- score a forecast with MAE, RMSE and MAPE
Example prompts for the agent
- decompose this sales series into trend and seasonality
- check stationarity and suggest ARIMA orders
- forecast the next 30 steps with a confidence interval
How to install Time Series Analysis
1Skills CLI (Vercel)
npx skills add aj-geddes/useful-ai-prompts --skill time-series-analysis -a claude-code2Manually: put the files in place
~/.claude/skills/time-series-analysis/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/time-series-analysis/
1Skills CLI (Vercel)
npx skills add aj-geddes/useful-ai-prompts --skill time-series-analysis -a codex2Manually: put the files in place
.agents/skills/time-series-analysis/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add aj-geddes/useful-ai-prompts --skill time-series-analysis -a cursor2Manually: put the files in place
.cursor/skills/time-series-analysis/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install aj-geddes/useful-ai-prompts time-series-analysis2Manually: put the files in place
.github/skills/time-series-analysis/SKILL.md1Skills CLI (Vercel)
npx skills add aj-geddes/useful-ai-prompts --skill time-series-analysis -a gemini-cli2Platform CLI
gemini skills install https://github.com/aj-geddes/useful-ai-prompts --path skills/time-series-analysisManually: put the files in place
.devin/skills/time-series-analysis/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add aj-geddes/useful-ai-prompts --skill time-series-analysis -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about Time Series Analysis
How do I install Time Series Analysis in Claude?
Run npx skills add aj-geddes/useful-ai-prompts --skill time-series-analysis -a claude-code. The skill lands in ~/.claude/skills/time-series-analysis/SKILL.md.
What does Time Series Analysis do?
It guides the agent through time series analysis: decomposition, stationarity testing, ARIMA and exponential smoothing, plus forecasts with accuracy metrics.
What does the skill need to run?
The examples use Python with pandas, numpy, matplotlib and statsmodels. Without those libraries the code will not execute.
Source text
SKILL.md · MIT
---
name: Time Series Analysis
description: Analyze temporal data patterns including trends, seasonality, autocorrelation, and forecasting for time series decomposition, trend analysis, and forecasting models
---
# Time Series Analysis
## Overview
Time series analysis examines data points collected over time to identify patterns, trends, and seasonality for forecasting and understanding temporal dynamics.
## When to Use
- Forecasting future values based on historical trends
- Detecting seasonality and cyclical patterns in data
- Analyzing trends over time in sales, stock prices, or website traffic
- Understanding autocorrelation and temporal dependencies
- Making time-based predictions with confidence intervals
- Decomposing data into trend, seasonal, and residual components
## Core Components
- **Trend**: Long-term directional movement
- **Seasonality**: Repeating patterns at fixed intervals
- **Cyclicity**: Long-term oscillations (non-fixed periods)
- **Stationarity**: Constant mean, variance over time
- **Autocorrelation**: Correlation with past values
## Key Techniques
- **Decomposition**: Separating trend, seasonal, residual components
- **Differencing**: Making data stationary
- **ARIMA**: AutoRegressive Integrated Moving Average models
- **Exponential Smoothing**: Weighted average of past values
- **SARIMA**: Seasonal ARIMA models
## Implementation with Python
```python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.seasonal import seasonal_decompose
from statsmodels.tsa.stattools import adfuller, acf, pacf
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.holtwinters import ExponentialSmoothing
# Create sample time series data
dates = pd.date_range('2020-01-01', periods=365, freq='D')
values = 100 + np.sin(np.arange(365) * 2*np.pi / 365) * 20 + np.random.normal(0, 5, 365)
ts = pd.Series(values, index=dates)
# Visualize time series
fig, axes = plt.subplots(2, 2, figsize=(14, 8))
axes[0, 0].plot(ts)
axes[0, 0].set_title('Original Time Series')
axes[0, 0].set_ylabel('Value')
# Decomposition
decomposition = seasonal_decompose(ts, model='additive', period=30)
axes[0, 1].plot(decomposition.trend)
axes[0, 1].set_title('Trend Component')
axes[1, 0].plot(decomposition.seasonal)
axes[1, 0].set_title('Seasonal Component')
axes[1, 1].plot(decomposition.resid)
axes[1, 1].set_title('Residual Component')
plt.tight_layout()
plt.show()
# Test for stationarity (Augmented Dickey-Fuller)
result = adfuller(ts)
print(f"ADF Test Statistic: {result[0]:.6f}")
print(f"P-value: {result[1]:.6f}")
print(f"Critical Values: {result[4]}")
if result[1] <= 0.05:
print("Time series is stationary")
else:
print("Time series is non-stationary - differencing needed")
# First differencing for stationarity
ts_diff = ts.diff().dropna()
result_diff = adfuller(ts_diff)
print(f"\nAfter differencing - ADF p-value: {result_diff[1]:.6f}")
# Autocorrelation and Partial Autocorrelation
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
plot_acf(ts_diff, lags=40, ax=axes[0])
axes[0].set_title('ACF')
plot_pacf(ts_diff, lags=40, ax=axes[1])
axes[1].set_title('PACF')
plt.tight_layout()
plt.show()
# ARIMA Model
arima_model = ARIMA(ts, order=(1, 1, 1))
arima_result = arima_model.fit()
print(arima_result.summary())
# Forecast
forecast_steps = 30
forecast = arima_result.get_forecast(steps=forecast_steps)
forecast_df = forecast.conf_int()
forecast_mean = forecast.predicted_mean
# Plot forecast
fig, ax = plt.subplots(figsize=(12, 5))
ax.plot(ts.index[-90:], ts[-90:], label='Historical')
ax.plot(forecast_df.index, forecast_mean, label='Forecast', color='red')
ax.fill_between(
forecast_df.index,
forecast_df.iloc[:, 0],
forecast_df.iloc[:, 1],
color='red', alpha=0.2
)
ax.set_title('ARIMA Forecast with Confidence Interval')
ax.legend()
ax.grid(True, alpha=0.3)
plt.show()
# Exponential Smoothing
exp_smooth = ExponentialSmoothing(
ts, seasonal_periods=30, trend='add', seasonal='add', initialization_method='estimated'
)
exp_result = exp_smooth.fit()
# Model diagnostics
fig = exp_result.plot_diagnostics(figsize=(12, 8))
plt.tight_layout()
plt.show()
# Custom moving average analysis
window_sizes = [7, 30, 90]
fig, ax = plt.subplots(figsize=(12, 5))
ax.plot(ts.index, ts.values, label='Original', alpha=0.7)
for window in window_sizes:
ma = ts.rolling(window=window).mean()
ax.plot(ma.index, ma.values, label=f'MA({window})')
ax.set_title('Moving Averages')
ax.legend()
ax.grid(True, alpha=0.3)
plt.show()
# Seasonal subseries plot
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
for i, month in enumerate(range(1, 5)):
month_data = ts[ts.index.month == month]
axes[i // 2, i % 2].plot(month_data.values)
axes[i // 2, i % 2].set_title(f'Month {month} Pattern')
plt.tight_layout()
plt.show()
# Forecast accuracy metrics
def calculate_forecast_metrics(actual, predicted):
mae = np.mean(np.abs(actual - predicted))
rmse = np.sqrt(np.mean((actual - predicted) ** 2))
mape = np.mean(np.abs((actual - predicted) / actual)) * 100
return {'MAE': mae, 'RMSE': rmse, 'MAPE': mape}
metrics = calculate_forecast_metrics(ts[-30:], forecast_mean[:30])
print(f"\nForecast Metrics:\n{metrics}")
# Additional analysis techniques
# Step 10: Seasonal subseries plots
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
for i, season in enumerate([1, 2, 3, 4]):
seasonal_ts = ts[ts.index.month % 4 == season % 4]
axes[i // 2, i % 2].plot(seasonal_ts.values)
axes[i // 2, i % 2].set_title(f'Season {season}')
plt.tight_layout()
plt.show()
# Step 11: Granger causality (for multiple series)
from statsmodels.tsa.stattools import grangercausalitytests
# Create another series for testing
ts2 = ts.shift(1).fillna(method='bfill')
try:
print("\nGranger Causality Test:")
print(f"Test whether ts2 Granger-causes ts:")
gc_result = grangercausalitytests(np.column_stack([ts.values, ts2.values]), maxlag=3)
except Exception as e:
print(f"Granger causality not performed: {str(e)[:50]}")
# Step 12: Autocorrelation and partial autocorrelation analysis
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
acf_values = acf(ts.dropna(), nlags=20)
pacf_values = pacf(ts.dropna(), nlags=20)
# Step 13: Seasonal strength
def seasonal_strength(series, seasonal_period=30):
seasonal = seasonal_decompose(series, model='additive', period=seasonal_period)
var_residual = np.var(seasonal.resid.dropna())
var_seasonal = np.var(seasonal.seasonal)
return 1 - (var_residual / (var_residual + var_seasonal)) if (var_residual + var_seasonal) > 0 else 0
ss = seasonal_strength(ts)
print(f"\nSeasonal Strength: {ss:.3f}")
# Step 14: Forecasting with uncertainty
fig, ax = plt.subplots(figsize=(12, 5))
ax.plot(ts.index[-60:], ts.values[-60:], label='Historical', linewidth=2)
# Multiple horizon forecasts
for steps_ahead in [10, 20, 30]:
try:
fc = arima_result.get_forecast(steps=steps_ahead)
fc_mean = fc.predicted_mean
ax.plot(pd.date_range(ts.index[-1], periods=steps_ahead+1)[1:],
fc_mean.values, marker='o', label=f'Forecast (+{steps_ahead})')
except:
pass
ax.set_title('Multi-step Ahead Forecasts')
ax.set_xlabel('Date')
ax.set_ylabel('Value')
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# Step 15: Model comparison summary
print("\nTime Series Analysis Complete!")
print(f"Original series length: {len(ts)}")
print(f"Trend strength: {1 - np.var(decomposition.resid.dropna()) / np.var((ts - ts.mean()).dropna()):.3f}")
print(f"Seasonal strength: {ss:.3f}")
```
## Stationarity
- **Stationary**: Mean, variance, autocorrelation constant over time
- **Non-stationary**: Trend or seasonal patterns present
- **Solution**: Differencing, log transformation, or detrending
## Model Selection
- **ARIMA**: Good for univariate forecasting
- **SARIMA**: Includes seasonal components
- **Exponential Smoothing**: Simpler, good for trends
- **Prophet**: Handles holidays and changepoints
## Evaluation Metrics
- **MAE**: Mean Absolute Error
- **RMSE**: Root Mean Squared Error
- **MAPE**: Mean Absolute Percentage Error
## Deliverables
- Decomposition analysis charts
- Stationarity test results
- ACF/PACF plots
- Fitted models with diagnostics
- Forecast with confidence intervals
- Accuracy metrics comparison
© aj-geddes · MIT · aj-geddes/useful-ai-prompts