One feature of the SuperSmoother is its ability to handle periodic signals. We'll demonstrate this here:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
# Use seaborn for plotting defaults.
# This can be safely commented-out if seaborn is not installed
import seaborn; seaborn.set()
# Create a periodic function with interesting structure
def func(t, period):
phase = t / period
modphase = phase + 0.1 * np.sin(2 * np.pi * phase)
return np.sin(2 * np.pi * modphase)
rng = np.random.RandomState(42)
t = 50 * rng.rand(100)
period = 10
dy = 0.1
y = func(t, period) + dy * rng.randn(len(t))
phase = t % period
def plot_data():
fig, ax = plt.subplots(2)
fig.subplots_adjust(hspace=0.25)
# Plot the data first
ax[0].errorbar(t, y, dy, fmt='.')
ax[0].set_xlabel('t')
# Plot the phased data below
ax[1].errorbar(phase, y, dy, fmt='.')
ax[1].set_xlabel('phase');
return ax
plot_data();
Let's take a look at how supersmoother handles this. Using the standard algorithm to smooth each plot, we can do the following:
from supersmoother import SuperSmoother
phase_fit = np.linspace(0, period, 1000)
t_fit = np.linspace(0, 50, 1000)
model = SuperSmoother()
y_t = model.fit(t, y, dy).predict(t_fit)
y_phase = model.fit(phase, y, dy).predict(phase_fit)
ax = plot_data()
ax[0].plot(t_fit, y_t, '-k', lw=1)
ax[1].plot(phase_fit, y_phase, '-k', lw=1);
Notice there are some issues here. In the upper plot, the data: the data is sparse in some locations, which makes for a poor model. Also, at the edges there is some extrapolation which does not look good.
In the bottom, phased plot, things look a bit better. But there is a discontinuity between the left and right edges because the algorithm is not considering points across the boundary.
We can improve on these by passing a period
argument, which enforces periodicity of the smoothed model:
model = SuperSmoother(period=period)
y_t = model.fit(t, y, dy).predict(t_fit)
y_phase = model.fit(phase, y, dy).predict(phase_fit)
ax = plot_data()
ax[0].plot(t_fit, y_t, '-k', lw=1)
ax[1].plot(phase_fit, y_phase, '-k', lw=1);