2
$\begingroup$

I'm trying to do time series forecasting with linear regression like it's done in this video: Radial basis forecasting starting from 5:50.

I understand the basic idea of basis, but I don't think I understood the usage of it in time series data correctly. I have a Pandas dataframe with daily timestamps and target variables. I tried writing radial basis function

def radial_basis(x, month):
    alpha = 0.5
    coef = -1/(2*alpha)
    return np.exp(coef*(x-month)**2)

and calculating basis for every month (x is row number). This didn't work.

Any tips on how I should try to do this?

$\endgroup$

3 Answers 3

0
$\begingroup$

I was able to solve this by myself. First you need to create a column that contains day of year values from the timestamps. Then apply radial_basis function for that column with month parameter being the middle day of every month. For example in January it's 15, February 45 etc.

With this method you can generate a spike for every month.

data_all['Day'] = data_all.Timestamp.dt.dayofyear

def radial_basis(x, month):
    alpha = 8
    coef = -1/(2*alpha)
    return np.exp(coef*(x-month)**2)

for i in range(12):
    col = 'RB' + str(i+1)
    data_all[col] = data_all.Day.apply(radial_basis, month=(15+30*i))

$\endgroup$
0
$\begingroup$

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.

def radial_basis(x, month, alpha):
    if x - month <= 365 / 2:
        return np.exp(- (x - month) ** 2 / (2 * alpha))
    else:
        return np.exp(- (x - month - 365) ** 2 / ( 2 * alpha))

This seems to work even for 366-day years.

$\endgroup$
0
$\begingroup$

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)
)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.