Skip to content

Cyclical feature encoding

Encode a repeating position with cosine and sine so its endpoints meet. Choose the period, phase and calendar clock explicitly; preserve timestamp information separately.

Cyclical feature encoding represents a position in a repeating cycle using coordinates that meet smoothly at the cycle boundary. The usual encoding replaces one numeric label with a cosine–sine pair. For a quant model using time-of-day inputs, this makes 23:00 and 00:00 neighbouring phases rather than treating their labels as 23 units apart. It expresses an assumption about similarity; it does not establish a predictable return pattern.
This is a form of feature engineering. The first decision is whether a cycle is meaningful at all. Hour of day has a natural wraparound; an arbitrary numbering of companies or instrument types does not.

Close the midnight seam

Choose a positive period PP and an origin t0t_0, measured in the same units as the input tt. Define

θ(t)=2πt−t0P,x(t)=(cos⁡θ(t),sin⁡θ(t)).\theta(t)=2\pi\frac{t-t_0}{P},\qquad \mathbf{x}(t)=\bigl(\cos\theta(t),\sin\theta(t)\bigr).
Angles are in radians. Taking the position modulo PP first gives the same mathematical result. The origin states which position has angle zero; changing a common fixed origin rotates the circle without changing pairwise distances. Here the coordinate order is cosine, then sine.

For a 24-hour wall-clock feature, set P=24P=24, t0=0t_0=0 and t=ht=h, with midnight labelled 0. Fractional hours can include minutes and seconds. The following values use illustrative clock labels, without dates or an exchange calendar:

Hour labelCosine coordinateSine coordinate
01.0000000.000000
10.9659260.258819
230.965926−0.258819

The raw label difference between 23 and 0 is 23. Their Euclidean distance after encoding is

∥x(23)−x(0)∥=2−2cos⁡(π/12)≈0.2610523844.\lVert\mathbf{x}(23)-\mathbf{x}(0)\rVert =\sqrt{2-2\cos(\pi/12)} \approx0.2610523844.
That is exactly the same chord length as between hours 0 and 1. It is a dimensionless feature-space distance, not 0.261 hours. The short separation across midnight now matches the short separation after midnight.
On an ordinal hour axis, 23 and 0 differ by 23. On the unit circle, hours 23 and 0 have chord distance 0.261052, equal to the distance between hours 0 and 1. Cosine is horizontal and sine is vertical.
On an ordinal hour axis, 23 and 0 differ by 23. On the unit circle, hours 23 and 0 have chord distance 0.261052, equal to the distance between hours 0 and 1. Cosine is horizontal and sine is vertical.
Original illustration with a stipulated 24-hour cycle. Equal one-hour phase steps have equal chords, including across midnight; dated elapsed time is a separate quantity.

Keep both coordinates. Sine alone gives the same value at hours 0 and 12, although the pair places them at opposite points, distance 2 apart. Even the pair intentionally loses the cycle number: an observation and another exactly one period later have identical coordinates. Retain a date, trend or elapsed-time input separately when that distinction matters.

The owned Basic Trigonometry lesson develops the unit circle, radians, period and phase through a stylised liquidity example. Its preview is public; the full lesson requires membership.

A calendar label is a modelling choice

A period should describe the intended mechanism, rather than being the largest number observed in a training sample. An hour sample missing the late evening still has a 24-label clock. Inferring its period from the sample maximum would change every encoded angle.

Intended informationDefine before encoding
Local time of dayNamed time zone, midnight origin and wall-clock convention
Position in a trading sessionOfficial session schedule, treatment of breaks and early closes, and whether position means elapsed minutes or fraction of that session
Day of weekSeven calendar days or a separately justified trading-session index; holidays make these different clocks
Month or annual positionWhether equal angular steps represent month labels or elapsed progress through a specified calendar year
Twelve equally spaced month labels represent twelve named categories in cyclic order. They do not say that months have equal durations. An annual clock also needs a leap-year policy. A session ending and the next session opening need not be economically interchangeable: a circular mapping joins its endpoints. Open/close indicators or a non-circular session-progress feature may better preserve that distinction. Complex seasonality also allows multiple relevant periods rather than forcing all calendar structure into one cycle.
Daylight-saving transitions make the clock choice consequential. A local wall-clock time can occur twice when clocks move back; some local times do not occur when clocks move forward. Both occurrences of a repeated hour receive the same hour encoding. Python's official time-zone documentation illustrates distinct UTC instants sharing a local clock time, with different offsets and fold values. Preserve an unambiguous timestamp and time-zone information. Choose local wall time for a local-clock hypothesis, or an explicitly defined UTC/elapsed-time clock for a different hypothesis; a sine–cosine transform cannot resolve the ambiguity itself.

Smooth inputs do not guarantee a flexible forecast

The official scikit-learn example demonstrates this representation and compares it with other encodings. It also shows why removing the midnight discontinuity does not automatically capture a complicated daily pattern.
With only one pair as seasonal inputs, linear regression can fit an intercept plus one sinusoidal wave. Sharp opening effects or several daily peaks may require higher harmonics, periodic splines, interactions or a more flexible model. Higher harmonics use integer multiples of the base angle, as in a Fourier series; they add expressive capacity and research choices. One-hot indicators can instead let each time bin have its own effect, without imposing circular closeness.
Fix the encoding convention before evaluating future observations. If periods, harmonic counts or other representation choices are selected from data, select them within chronological development folds and preserve the final test period. A known clock transform needs no fitted sample mean, but its tuning can still introduce look-ahead bias. Judge the representation by the task and subsequent evaluation, not by how neatly it draws a circle.

Sources

Last updated
  • feature engineering
  • time series
  • seasonality
  • calendar features
← Back to the glossaryBack to top ↑