Hour 23 and hour 0 are one hour apart. A model reading them as the numbers 23 and 0 sees them as the two most distant points in the feature — so midnight looks maximally unlike 11pm, and every pattern that straddles it is invisible.
The fix is to stop using one number. Place each value on a circle and hand the model its two coordinates:
Task: write cyclic_encode(values, period) returning a two-item list [sin, cos] per value, each rounded to 4 decimal places.
period is the length of the cycle: 24 for hours, 7 for days of the week, 12 for months.sin first, cos second.0 and a value of period land on the same point, which is the whole purpose — the encoding wraps around.Neither function alone is enough, and it's worth seeing why. sin gives hour 6 and hour 18 different values but hour 3 and hour 9 the same one. cos has the same flaw a quarter-turn around. Only the pair pins down a unique position on the circle, which is why this is always two columns and never one.
The property you've bought: straight-line distance between two encoded points now tracks their distance around the cycle. Hour 23 and hour 0 sit next to each other on the circle, so the model sees them as near-identical — exactly as they should be.