How to Add Calendar and Time Features¶
This guide shows you how to derive calendar, holiday, Fourier, and trend features from the time column and pass them to a forecaster as deterministic inputs.
Prerequisites¶
- yohou installed (Installation)
- Familiarity with transformers and
actual_transformer(How to Use Preprocessing Transformers) - Background on time features (Preprocessing)
Try it interactively¶
-
How to Add Calendar, Fourier, and Holiday Features
Enrich your feature matrix with time-derived signals using CalendarFeatureTransformer, FourierFeatureTransformer, and HolidayFeatureTransformer.
Extract Calendar Features¶
CalendarFeatureTransformer extracts integer features from timestamps. Pass a list of feature names, or leave features=None to auto-detect all features applicable to your data's frequency:
from yohou.preprocessing import CalendarFeatureTransformer
from yohou.datasets import fetch_electricity_demand
data = fetch_electricity_demand()
y = data.frame
transformer = CalendarFeatureTransformer(features=["month", "day_of_week", "hour"])
X = transformer.fit_transform(y)
# Output columns: cal_month, cal_day_of_week, cal_hour
Available features include "year", "month", "quarter", "week", "day_of_week", "day_of_month", "day_of_year", "hour", "minute", and boolean indicators like "is_weekend", "is_month_start", "is_month_end", "is_quarter_start", "is_quarter_end", "is_year_start", "is_year_end".
Frequency aware
Sub-daily features ("hour", "minute") are only applicable to sub-daily data. When features=None, the transformer inspects the data interval and extracts only what makes sense. After fitting, check transformer.applicable_features_ to see which features were selected.
On a UTC-indexed frame, cal_hour is a UTC hour, so the local daily cycle drifts by an hour across a daylight-saving boundary. Pass time_zone to compute the features from local wall-clock time instead:
# "time" is timezone-aware UTC; features are read in America/Chicago.
transformer = CalendarFeatureTransformer(features=["hour", "day_of_week"], time_zone="America/Chicago")
X = transformer.fit_transform(y)
# cal_hour is now the local hour
The conversion is applied only when extracting feature values: the output time column is returned unchanged, so it stays a valid join key against your target and other feature frames (which are typically UTC-indexed). time_zone requires a timezone-aware time column.
Mark Holidays¶
HolidayFeatureTransformer creates a binary indicator column and optional proximity features showing distance to the nearest holiday:
from yohou.preprocessing import HolidayFeatureTransformer
import polars as pl
from datetime import date
holidays = pl.DataFrame({
"date": [date(2024, 1, 1), date(2024, 7, 4), date(2024, 12, 25)]
})
transformer = HolidayFeatureTransformer(
holidays=holidays,
days_to_next=True,
days_since_last=True,
)
X = transformer.fit_transform(y)
# Output columns: holiday_indicator, holiday_days_to_next, holiday_days_since_last
The holidays DataFrame needs a "date" column of Date or Datetime type. Set days_to_next=True or days_since_last=True to add integer columns measuring the distance (in days) to surrounding holidays.
Add Fourier Features¶
FourierFeatureTransformer captures smooth seasonal patterns with sine/cosine pairs at specified harmonics:
from yohou.preprocessing import FourierFeatureTransformer
transformer = FourierFeatureTransformer(seasonality=24, harmonics=[1, 2, 3])
X = transformer.fit_transform(y)
# Output columns: fourier_24_sin_1, fourier_24_cos_1, fourier_24_sin_2, ...
Set seasonality to the period length in time steps (e.g., 24 for daily cycles in hourly data, 365.25 for yearly cycles in daily data). Use more harmonics for sharper seasonal shapes, fewer for smoother patterns. Harmonics must satisfy the Nyquist limit: each harmonic \(k\) must be at most \(S/2\) where \(S\) is the seasonality.
Flag Daylight-Saving Transitions¶
DaylightSavingFeatureTransformer captures the two daylight-saving effects a UTC-indexed frame cannot see: the summer/winter clock offset (which shifts the local diurnal cycle by an hour) and the 23- or 25-hour transition days:
from yohou.preprocessing import DaylightSavingFeatureTransformer
# The "time" column must be timezone-aware; time_zone is the zone whose
# daylight-saving regime is evaluated (any input zone is converted into it).
transformer = DaylightSavingFeatureTransformer(time_zone="America/Chicago")
X = transformer.fit_transform(y)
# Output columns: dst_in_effect, dst_transition_day
The time_zone parameter names the zone whose daylight-saving regime is evaluated, not the input's zone. Pass features=["in_effect", "transition_day", "transition_type"] to also emit a signed flag (+1 on a spring-forward date, -1 on a fall-back date). in_effect requires sub-daily data and is dropped on daily-or-coarser frequencies; transition_day/transition_type apply at any frequency. The "time" column must be timezone-aware (a naive datetime or a Date is rejected at fit, since an offset needs both an instant and a zone).
Create a Trend Index¶
TimeIndexTransformer converts timestamps to a numeric index, useful for capturing linear or polynomial trends:
from yohou.preprocessing import TimeIndexTransformer
transformer = TimeIndexTransformer(normalize=True, degree=2)
X = transformer.fit_transform(y)
# Output columns: time_index, time_index_2
With degree=1 (the default), the transformer produces a single time_index column. Higher degrees add polynomial terms (time_index_2, time_index_3, etc.). Set normalize=True to scale the index to [0, 1] based on the training data length, which improves numerical stability for polynomial features.
Combine Multiple Time Features¶
Use FeatureUnion to run multiple time feature transformers in parallel and concatenate their outputs, then pass the result as actual_transformer to any forecaster:
from yohou.compose import FeatureUnion
from yohou.preprocessing import (
CalendarFeatureTransformer,
FourierFeatureTransformer,
TimeIndexTransformer,
)
from yohou.point import PointReductionForecaster
from sklearn.linear_model import Ridge
features = FeatureUnion([
("calendar", CalendarFeatureTransformer(features=["month", "day_of_week", "hour"])),
("fourier", FourierFeatureTransformer(seasonality=24, harmonics=[1, 2, 3])),
("trend", TimeIndexTransformer(normalize=True)),
])
forecaster = PointReductionForecaster(
estimator=Ridge(),
actual_transformer=features,
)
forecaster.fit(y, forecasting_horizon=24)
predictions = forecaster.predict()
For more complex compositions (sequential chaining, nesting), see How to Compose Feature Pipelines.
actual_transformer vs X_future
When time features are passed via actual_transformer, the forecaster generates them automatically at both fit and predict time. If you generate calendar or Fourier features externally (outside actual_transformer), pass them via X_future at both fit() and predict() time, since they are deterministic and known in advance. See Exogenous Features for details.
See Also¶
- Preprocessing: full details on each transformer
- How to Compose Feature Pipelines: sequential and parallel transformer composition
- Exogenous Features: when and how to use external features
- API Reference: yohou.preprocessing