Закодируйте час суток так, чтобы 23:00 и 00:00 оказались рядом.
Час суток цикличен — 23:00 отстоит от 00:00 на один час, но обычный целочисленный столбец разносит их на 23.
Ограничения:
- Верните два новых столбца вместо сырого часа.
- Кодирование должно работать для любого периода, поэтому период передаётся аргументом.
- Используйте только numpy и pandas.
import numpy as np
import pandas as pd
def encode_cyclical(df: pd.DataFrame, col: str, period: int) -> pd.DataFrame:
# TODO: добавьте столбцы <col>_sin и <col>_cos и удалите исходный столбец
...
Допишите реализацию.
Отобразите значение на окружность — возьмите угол два пи, умноженный на час и делённый на 24, и выдайте его синус и косинус двумя столбцами. Окружность замкнута, поэтому час 23 и час 0 оказываются рядом, чего целый столбец не выражает.
- ✗Оставлять исходный целый час, из-за чего модель по-прежнему видит полночь далеко от 23:00
- ✗Выдавать только синус, из-за чего два разных часа схлопываются в одно значение
- ✗Жёстко зашивать период 24 и переиспользовать помощник для месяца или дня недели
- →Почему один столбец с синусом схлопывает два разных часа в одно значение?
- →Даёт ли это кодирование что-нибудь градиентному бустингу на деревьях?
Значение отображается на окружность: угол равен 2*pi*value/period, а признаками становятся его синус и косинус. Окружность замкнута, поэтому значения на её концах оказываются рядом.
import numpy as np
import pandas as pd
def encode_cyclical(df: pd.DataFrame, col: str, period: int) -> pd.DataFrame:
out = df.copy()
angle = 2 * np.pi * out[col].astype(float) / period
out[f"{col}_sin"] = np.sin(angle)
out[f"{col}_cos"] = np.cos(angle)
return out.drop(columns=[col])
df = pd.DataFrame({"hour": [23, 0, 12]})
enc = encode_cyclical(df, "hour", 24)
Расстояние между часами 23 и 0 в паре (sin, cos) такое же, как между 0 и 1, тогда как для сырого целого оно было бы 23. Косинус обязателен: только синус даёт одно и то же значение для двух разных часов. Для месяца передайте период 12, для дня недели — 7.