@@ -138,6 +138,8 @@ def __init__(
138
138
raise ValueError ("Invalid impute_method given." )
139
139
if self .boundary_method not in valid_boundary_methods :
140
140
raise ValueError ("Invalid boundary_method given." )
141
+ if self .window_length <= 1 :
142
+ raise ValueError ("Window length is too short." )
141
143
142
144
if smoother_name == "savgol" :
143
145
# The polynomial fitting is done on a past window of size window_length
@@ -165,21 +167,41 @@ def smooth(self, signal: Union[np.ndarray, pd.Series]) -> Union[np.ndarray, pd.S
165
167
A smoothed 1D signal. Returns an array of the same type and length as
166
168
the input.
167
169
"""
170
+ # If all nans, pass through
171
+ if np .all (np .isnan (signal )):
172
+ return signal
173
+
168
174
is_pandas_series = isinstance (signal , pd .Series )
175
+ pandas_index = signal .index if is_pandas_series else None
169
176
signal = signal .to_numpy () if is_pandas_series else signal
170
177
171
- signal = self .impute (signal )
178
+ # Find where the first non-nan value is located and truncate the initial nans
179
+ ix = np .where (~ np .isnan (signal ))[0 ][0 ]
180
+ signal = signal [ix :]
172
181
173
- if self .smoother_name == "savgol" :
174
- signal_smoothed = self .savgol_smoother (signal )
175
- elif self .smoother_name == "left_gauss_linear" :
176
- signal_smoothed = self .left_gauss_linear_smoother (signal )
177
- elif self .smoother_name == "moving_average" :
178
- signal_smoothed = self .moving_average_smoother (signal )
179
- else :
182
+ # Don't smooth in certain edge cases
183
+ if len (signal ) < self .poly_fit_degree or len (signal ) == 1 :
180
184
signal_smoothed = signal .copy ()
181
-
182
- signal_smoothed = signal_smoothed if not is_pandas_series else pd .Series (signal_smoothed )
185
+ else :
186
+ # Impute
187
+ signal = self .impute (signal )
188
+
189
+ # Smooth
190
+ if self .smoother_name == "savgol" :
191
+ signal_smoothed = self .savgol_smoother (signal )
192
+ elif self .smoother_name == "left_gauss_linear" :
193
+ signal_smoothed = self .left_gauss_linear_smoother (signal )
194
+ elif self .smoother_name == "moving_average" :
195
+ signal_smoothed = self .moving_average_smoother (signal )
196
+ elif self .smoother_name == "identity" :
197
+ signal_smoothed = signal
198
+
199
+ # Append the nans back, since we want to preserve length
200
+ signal_smoothed = np .hstack ([np .nan * np .ones (ix ), signal_smoothed ])
201
+ # Convert back to pandas if necessary
202
+ if is_pandas_series :
203
+ signal_smoothed = pd .Series (signal_smoothed )
204
+ signal_smoothed .index = pandas_index
183
205
return signal_smoothed
184
206
185
207
def impute (self , signal ):
@@ -283,7 +305,7 @@ def left_gauss_linear_smoother(self, signal):
283
305
284
306
def savgol_predict (self , signal , poly_fit_degree , nr ):
285
307
"""Predict a single value using the savgol method.
286
-
308
+
287
309
Fits a polynomial through the values given by the signal and returns the value
288
310
of the polynomial at the right-most signal-value. More precisely, for a signal of length
289
311
n, fits a poly_fit_degree polynomial through the points signal[-n+1+nr], signal[-n+2+nr],
@@ -312,7 +334,8 @@ def savgol_predict(self, signal, poly_fit_degree, nr):
312
334
def savgol_coeffs (self , nl , nr , poly_fit_degree ):
313
335
"""Solve for the Savitzky-Golay coefficients.
314
336
315
- The coefficients c_i give a filter so that
337
+ Solves for the Savitzky-Golay coefficients. The coefficients c_i
338
+ give a filter so that
316
339
y = sum_{i=-{n_l}}^{n_r} c_i x_i
317
340
is the value at 0 (thus the constant term) of the polynomial fit
318
341
through the points {x_i}. The coefficients are c_i are calculated as
@@ -386,7 +409,7 @@ def savgol_smoother(self, signal):
386
409
# - identity keeps the original signal (doesn't smooth)
387
410
# - nan writes nans
388
411
if self .boundary_method == "shortened_window" : # pylint: disable=no-else-return
389
- for ix in range (len (self .coeffs )):
412
+ for ix in range (min ( len (self .coeffs ), len ( signal ) )):
390
413
if ix == 0 :
391
414
signal_smoothed [ix ] = signal [ix ]
392
415
else :
0 commit comments