Capturing seasonal component using Fourier Decomposition

Dummy Data

Using the definition of a fourier series, $$ \begin{aligned} S_i(t) &= \sum_{n=1}^N\left(a_n \cos\left(\frac{2\pi nt}{P_i}\right) + b_n \sin\left(\frac{2\pi nt}{P_i}\right)\right) \\ \end{aligned} $$ we create two series ($i\in\{1,2\}$) where $P_1 = 365$ and $P_2 = 30.5$ representing yearly and monthly seasonalities respectively for $N=3$.

P = 365
P2 = 30.5
N = 365
t = np.arange(N)

# Coefficients
an = [1, 0.5, -1.5]
bn = [1, -0.5, 1.5]

an2 = [-1, 0.5, -1.5]
bn2 = [1, -0.5, 2]

s = [a*np.cos(2*np.pi*(n+1)*t/P) + b*np.sin(2*np.pi*(n+1)*t/P)
     for n,(a,b) in enumerate(zip(an, bn))]
s2 = [a*np.cos(2*np.pi*(n+1)*t/P2) + b*np.sin(2*np.pi*(n+1)*t/P2)
     for n,(a,b) in enumerate(zip(an2, bn2))]

y = sum(s) + sum(s2)

plt.subplot(2,1,1)
plt.plot(t, sum(s), label='Yearly')
plt.plot(t, sum(s2), label='Monthly')
plt.legend()
plt.subplot(2,1,2)
plt.plot(t, y, label='Time Series')
plt.legend()
plt.show()

class FourierModel[source]

FourierModel(p:float=365.25, scale:float=1, n:int=7) :: Module

Block that outputs sin's and cos' as basis functions. parameters:

  • p: period
  • scale: time axis scaling factor
  • n: number of fourier components

class Seasonal[source]

Seasonal(y_n=10, m_n=5, w_n=3, scale=1) :: Module

Combination of Fourier Blocks that gives weekly, monthly and yearly seasonality. parameters:

  • y_n: Number of yearly components
  • m_n: Number of monthly components
  • w_n: Number of weekly components
  • scale: time axis scaling factor

Testing

model = FourierModel()
learner = Learner(db, model, loss_func=F.l1_loss)
wd = 0
learner.lr_find(wd=wd)
learner.recorder.plot(skip_end=0)
LR Finder is complete, type {learner_name}.recorder.plot() to see the graph.
epochs = 5
learner.fit_one_cycle(epochs, 2e-1, wd=wd)
epoch train_loss valid_loss time
0 2.521029 1.777201 00:00
1 2.403449 1.926800 00:00
2 2.249872 2.125787 00:00
3 2.135793 2.258477 00:00
4 2.054816 2.283656 00:00
y2 = learner.model(torch.Tensor(t)[:,None])
plt.plot(t, y, label='actual')
plt.plot(t, y2, label='prediction')
plt.show()
learner.model.plot()
model = Seasonal(w_n=0)
learner = Learner(db, model, loss_func=F.l1_loss)
wd = 0
learner.lr_find(wd=wd)
learner.recorder.plot(skip_end=0)
LR Finder is complete, type {learner_name}.recorder.plot() to see the graph.
epochs = 5
learner.fit_one_cycle(epochs, 2e-1, wd=wd)
y2 = learner.model(torch.Tensor(t)[:,None])
plt.plot(t, y, label='actual')
plt.plot(t, y2, label='prediction')
plt.show()
epoch train_loss valid_loss time
0 2.303246 1.518271 00:00
1 2.102577 1.277658 00:00
2 1.778894 1.225464 00:00
3 1.478693 1.256059 00:00
4 1.256826 1.244654 00:00
learner.model.plot_components()