We could generalize & prettify the code like this. Kindly let me know if you can improve this further.
from datetime import datetime
start_date = datetime.strptime("2023-01-01", "%Y-%m-%d")
end_date = datetime.strptime("2023-12-31", "%Y-%m-%d")
df = pd.DataFrame(
columns = ["Date"],
data = pd.date_range(start_date, end_date, freq="D")
)
def radial_basis(x, subgroup, no_of_days_in_group, alpha = 10):
numerator = x-subgroup
# The following definition makes sure that you always get symmetric functions, even when you transition to another year. Otherwise, you would get jumps between December 31 and January 1st. This seems to work even for 366-day years.
numerator = np.where(
numerator > no_of_days_in_group/2,
numerator - no_of_days_in_group,
numerator
)
return np.exp(
-1/(2 * alpha) * np.square(numerator)
)
def add_radial_basis(df, subgroup, group, alpha = 10):
no_of_days = dict(
Year = 365,
Month = 30,
Week = 7,
Day = 1
)
no_of_days_in_subgroup = no_of_days[subgroup]
no_of_days_in_group = no_of_days[group]
no_of_subgroups_in_group = int(no_of_days_in_group/no_of_days_in_subgroup)
date_col = df["Date"].dt
temp_dict = dict()
for i in range(no_of_subgroups_in_group):
col_name = f"{subgroup}_{i+1}_of_{group}"
if group == "Year":
col = date_col.dayofyear
elif group == "Month":
col = date_col.day
elif group == "Week":
col = date_col.dayofweek
temp_dict[col_name] = radial_basis(
col.astype(np.int32),
no_of_days_in_group = no_of_days_in_group,
subgroup = no_of_days_in_subgroup * (i+0.5),
alpha = alpha
).astype(np.float16) # reduce overhead
return pd.concat([df, pd.DataFrame(temp_dict)], axis=1)
df = (
df
.pipe(add_radial_basis, subgroup="Month", group="Year", alpha=200)
#.pipe(add_radial_basis, subgroup="Week", group="Year", alpha=10)
#.pipe(add_radial_basis, subgroup="Week", group="Month", alpha=10)
#.pipe(add_radial_basis, subgroup="Day", group="Month", alpha=5)
#.pipe(add_radial_basis, subgroup="Day", group="Year", alpha=5)
)