RollingPoly2
Description
The RollingPoly2 class fits a quadratic polynomial (second-degree equation) to the data within a specified moving window. This rolling quadratic fit provides insights into the data’s overall trend, rate of change, and curvature. Depending on the derivative_order, the function can return:
0: The y-value at the endpoint of the fitted quadratic curve, offering a smooth continuation of the data.
1: The slope (first derivative) at the endpoint, representing the rate of change.
2: The curvature (second derivative) at the endpoint, which captures the concavity of the data.
This method, which extends the idea of a causal Savitzky-Golay filter, enables more nuanced data analysis by capturing both linear and quadratic trends within each window.
Parameters:
window_size: Specifies the size of the rolling window.derivative_order:0: The y-value at the endpoint of the fitted quadratic curve, offering a smooth continuation of the data.1: The slope (first derivative) at the endpoint, representing the rate of change.2: The curvature (second derivative) at the endpoint, which captures the concavity of the data.
start_policy: Defines how the function handles the initial phase when fewer thanwindow_sizedata points are available. This parameter accepts one of the following three values:"strict": ReturnsNaNfor all calculations untilwindow_sizeelements have been processed."expanding": Adapts the computation by dynamically reducing the window size to include all available data, starting from a single point and growing untilwindow_sizeis reached."zero": Simulates a full initial window of zeros, effectively pre-filling the data stream withwindow_sizezeros before processing the actual input.
Usage Example and Plot
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from screamer import RollingPoly2
# Generate example data
data = np.cumsum(np.random.normal(size=300))
# Create subplots with specified row heights and shared x-axis
fig = make_subplots(
rows=3, cols=1,
shared_xaxes=True,
row_heights=[1/3, 1/3, 1/3],
vertical_spacing=0.1
)
# RollingPoly2 for endpoint (derivative_order=0)
endpoint_data = RollingPoly2(window_size=30, derivative_order=0)(data)
# RollingPoly2 for slope (derivative_order=1)
slope_data = RollingPoly2(window_size=30, derivative_order=1)(data)
# RollingPoly2 for curvature (derivative_order=2)
curvature_data = RollingPoly2(window_size=30, derivative_order=2)(data)
# Add traces for input data and results with different derivative orders
fig.add_trace(go.Scatter(y=data, mode='lines', name='Input Data'), row=1, col=1)
fig.add_trace(go.Scatter(y=endpoint_data, mode='lines', name='Rolling Endpoint (Order 0)', line=dict(color='green')), row=1, col=1)
fig.add_trace(go.Scatter(y=slope_data, mode='lines', name='Rolling Slope (Order 1)', line=dict(color='blue')), row=2, col=1)
fig.add_trace(go.Scatter(y=curvature_data, mode='lines', name='Rolling Curvature (Order 2)', line=dict(color='purple')), row=3, col=1)
# Update layout with titles and axis labels
fig.update_layout(
title="RollingPoly2 with Window Size 30",
xaxis_title="Index",
yaxis=dict(title="Input Data and endpoint"),
yaxis2=dict(title="RollingPoly2 Slope"),
yaxis3=dict(title="RollingPoly2 Curvature"),
margin=dict(l=20, r=20, t=120, b=20),
legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1)
)
fig.show()
Implementation Details
Algorithm
RollingPoly2 uses least-squares regression to fit a quadratic function within each window. The class allows returning either the endpoint value, the slope, or the curvature at the endpoint, based on derivative_order. This fitting method effectively captures both linear and non-linear trends, making it suitable for applications needing insights into the rate of change and concavity within the data.
Complexity
Time Complexity: O(1) per element.
Space Complexity: O(window_size), since only elements within the current window are stored.
Performance
RollingPoly2is hundreds times faster thanPandas rolling apply, and the speed is constant, indepenent of the windows size.