TBATS
Handles multiple seasonal patterns and complex seasonality with non-integer periods
TBATS (Trigonometric seasonality, Box-Cox transformation, ARMA errors, Trend, and Seasonal components) is designed for time series with multiple seasonal patterns, complex seasonality, and non-integer seasonal periods. It excels where standard methods struggle with multiple overlapping cycles.
When to Use TBATS
TBATS is best suited for:
- Time series with multiple seasonal patterns (e.g., hourly data with both daily and weekly cycles)
- Complex seasonality that other models can't capture
- Non-integer seasonal periods (e.g., 365.25 days for yearly)
- Data with changing variance requiring stabilization
- When SARIMA is too limiting (single seasonality only)
- Forecasting tasks where capturing all seasonal components is critical
Strengths
- Handles multiple seasonal patterns simultaneously
- Supports non-integer seasonal periods (e.g., 365.25 for leap years)
- Automatic variance stabilization via Box-Cox transformation
- Combines trend, seasonality, and ARMA errors in one framework
- No need to manually deseasonalize
- Flexible modeling of complex seasonal structures
- Provides uncertainty intervals
- Works well for high-frequency data (hourly, sub-daily)
Weaknesses
- Computationally intensive (slow training)
- High memory usage for large seasonal periods
- Many internal parameters (complexity)
- Can overfit with insufficient data
- Limited to univariate forecasting
- Cannot incorporate exogenous variables
- Less interpretable than simpler models
- Requires substantial history (multiple complete cycles of all seasons)
- Forecast uncertainty may be underestimated
Parameters
Common Time Series Parameters
All time series models share these parameters:
- Timestamp Column (required): Column containing dates/times
- Target Column (required): Numeric value to forecast
- Frequency (optional): Time spacing (D, H, W, M). Auto-inferred if not specified
- Forecast Steps (required, default=1): How many periods to predict
TBATS-Specific Parameters
Box-Cox Transform
- Type: Boolean or null
- Default: null (auto-detect)
- Options: [true, false, null]
- Description: Whether to apply Box-Cox transformation for variance stabilization
- true: Force Box-Cox transformation (handles heteroscedasticity)
- false: No transformation (use for homoscedastic data)
- null: Automatically decide based on likelihood
- Guidance:
- Use true if variance grows with level
- Use false if variance is constant
- Use null (recommended) to let the model decide
Use Trend
- Type: Boolean or null
- Default: null (auto-detect)
- Options: [true, false, null]
- Description: Whether to include a trend component
- true: Force trend inclusion
- false: No trend (stationary level)
- null: Automatically decide
- Guidance:
- Use true for clearly trending data
- Use false for stationary series
- Use null for automatic detection
Damped Trend
- Type: Boolean or null
- Default: null (auto-detect)
- Options: [true, false, null]
- Description: Whether the trend should decay over time
- true: Trend dampens (flattens) in long forecasts
- false: Trend continues linearly
- null: Automatically decide
- Guidance:
- Use true to prevent unrealistic long-term extrapolation
- Use false for persistent trends
- Use null for automatic selection
Seasonal Periods
- Type: List of floats/integers or null
- Default: null (auto-detect)
- Description: List of seasonal periods to model (e.g., [7, 365.25] for daily data with weekly and yearly patterns)
- Examples:
- [24, 168] for hourly data (daily and weekly cycles)
- [7] for daily data (weekly cycle only)
- [12] for monthly data (yearly cycle)
- [7, 365.25] for daily data (weekly and yearly, accounting for leap years)
- Important: Can specify non-integer periods (e.g., 365.25)
- Guidance: Leave as null to auto-detect, or specify known seasonal periods
Configuration Tips
Auto Configuration (Recommended)
For most cases, let TBATS auto-detect:
use_box_cox=null
use_trend=null
use_damped_trend=null
seasonal_periods=nullTBATS will test various configurations and select the best.
Specifying Multiple Seasonalities
For hourly data with daily and weekly patterns:
seasonal_periods=[24, 168]- 24 hours in a day
- 168 hours in a week (7 × 24)
For daily data with weekly and yearly patterns:
seasonal_periods=[7, 365.25]- 7 days in a week
- 365.25 days in a year (accounts for leap years)
When to Manually Set Parameters
Use Box-Cox (use_box_cox=true):
- When variance clearly grows with the level (e.g., sales increasing in magnitude and volatility)
- Financial data with heteroscedasticity
No Box-Cox (use_box_cox=false):
- When variance is stable
- Already transformed data (log, sqrt)
Force Trend (use_trend=true):
- Clear upward/downward movement over time
- Business growth scenarios
No Trend (use_trend=false):
- Stationary series fluctuating around a mean
- Pre-detrended data
Damped Trend (use_damped_trend=true):
- Trends expected to level off
- Conservative long-term forecasts
Data Requirements
TBATS requires substantial data:
- At least 2 complete cycles of each seasonal pattern
- Example: For [24, 168], need at least 2 weeks (336 hours) of data
- More data is better (3-4+ cycles recommended)
Computational Considerations
TBATS can be slow for:
- Large seasonal periods (e.g., 365)
- Multiple seasonal periods (e.g., [24, 168, 8760])
- Long time series (10,000+ observations)
Speed Tips:
- Specify seasonal_periods instead of auto-detection
- Aggregate data to reduce frequency if possible
- Use subset of data for initial experiments
Common Issues and Solutions
Issue: Training Takes Forever
Solution:
- Manually specify seasonal_periods (skip auto-detection)
- Reduce seasonal periods (aggregate data)
- Hourly → Daily: reduces [24, 168] to [7]
- Daily → Weekly: reduces [7, 365] to [52]
- Use a subset of data for testing
- Consider Prophet as a faster alternative for multiple seasonalities
Issue: Model Doesn't Capture All Seasonalities
Solution:
- Explicitly set seasonal_periods=[period1, period2, ...]
- Ensure at least 2 complete cycles of each period in data
- Verify periods are correct (e.g., 168 for weekly in hourly, not 7)
- Check that seasonality is actually present (plot and inspect)
Issue: Memory Errors
Solution:
- TBATS is memory-intensive for large seasonal periods
- Aggregate data to smaller frequency
- Use fewer seasonal components
- Switch to Prophet or seasonal decomposition
Issue: Overfitting (Poor Out-of-Sample Performance)
Solution:
- TBATS has many parameters; can overfit with limited data
- Ensure sufficient data (3-4+ seasonal cycles minimum)
- Simplify by removing some seasonal periods
- Use cross-validation to assess generalization
- Compare with simpler models (SARIMA, Prophet)
Issue: Forecasts Have Unrealistic Trends
Solution:
- Enable damped trend: use_damped_trend=true
- Or disable trend if not needed: use_trend=false
- Check if your trend is actually sustainable
- Consider manual specification vs auto-detection
Issue: Need External Variables
Solution:
- TBATS doesn't support exogenous variables
- Use Prophet with additional regressors (also handles multiple seasonalities)
- Or decompose seasonality with TBATS, then model residuals with external features
Issue: Confidence Intervals Too Narrow
Solution:
- TBATS may underestimate uncertainty
- Use bootstrap methods for more realistic intervals
- Compare with simpler models (SARIMA) for interval checks
- Consider ensemble forecasts
Issue: Can't Handle Non-Integer Seasonality
Solution:
- This is where TBATS excels! Specify seasonal_periods=[365.25] for yearly daily data
- Or seasonal_periods=[52.18] for weekly in daily data if precise
Example Use Cases
Hourly Electricity Demand (Daily + Weekly)
seasonal_periods=[24, 168]
use_box_cox=true
use_trend=true
use_damped_trend=trueCaptures intraday peaks and weekend vs weekday differences, with growing demand.
Daily Sales (Weekly + Yearly)
seasonal_periods=[7, 365.25]
use_box_cox=null
use_trend=true
use_damped_trend=falseModels day-of-week and seasonal (holiday) patterns with trend.
15-Minute Call Center Volume (Hourly + Daily + Weekly)
seasonal_periods=[4, 96, 672]- 4 periods per hour (15-min intervals)
- 96 periods per day (24 × 4)
- 672 periods per week (7 × 96)
Very complex; may need aggregation to hourly.
Daily Website Traffic (Weekly Only)
seasonal_periods=[7]
use_trend=falseSimpler case; might use SARIMA instead (faster).
Sub-Hourly Energy Prices (Multiple Cycles)
seasonal_periods=[12, 288]- 12 periods in an hour (5-min data)
- 288 periods in a day
TBATS handles non-standard frequencies well.
Comparison with Other Models
vs SARIMA:
- TBATS: Multiple seasonalities, non-integer periods, slower
- SARIMA: Single seasonality, faster, simpler
vs Prophet:
- TBATS: More statistically rigorous, better for complex seasonality
- Prophet: Faster, handles exogenous variables, interpretable components
vs Exponential Smoothing:
- TBATS: Multiple seasonalities, Box-Cox, ARMA errors
- Exponential Smoothing: Simpler, faster, single seasonality
vs Seasonal Decomposition + ARIMA:
- TBATS: Integrated approach, automatic
- Decomposition: More manual, flexible, interpretable
Technical Details
TBATS Components
- Trigonometric seasonality: Uses Fourier terms to model seasonal patterns
- Box-Cox transformation: Stabilizes variance
- ARMA errors: Models residual autocorrelation
- Trend: Local level and slope
- Seasonal: Multiple seasonal components
Model Complexity
TBATS can have dozens to hundreds of parameters depending on:
- Number of seasonal periods
- Fourier terms per seasonal component
- ARMA order for errors
This flexibility is powerful but increases risk of overfitting.
Computational Complexity
Time complexity scales with:
- Number of observations (O(n))
- Number of seasonal periods (exponential in selection phase)
- Fourier terms (more terms = more parameters)
Practical Recommendations
- Start Simple: Try Prophet or SARIMA first
- Use TBATS When: Other models fail to capture multiple seasonalities
- Auto-Detect: Let TBATS choose parameters initially
- Validate: Use cross-validation for model selection
- Compare: Benchmark against simpler models
- Production: Consider forecast speed and resource requirements
TBATS is a powerful but heavy tool. Use it when its unique capabilities (multiple/non-integer seasonalities) are truly needed.