Skip to content

Commit 6f8bf18

Browse files
committed
added deprecation messages to tons of functions throughtout the repo, those which are really special cases/hyperparameter choices of a more general method; added a new ubermethod in the smooth_finite_difference module to simplify some plots and consolidate some thinking; updated the notebooks to agree with this brave new world; futzed with __init__.py files to also agree; and the optimization code; and reordered some things in the readme and tests because I now think iterated FD is logically second in the stack
1 parent 0535d37 commit 6f8bf18

14 files changed

Lines changed: 412 additions & 742 deletions

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ Python methods for numerical differentiation of noisy data, including multi-obje
2626

2727
PyNumDiff is a Python package that implements various methods for computing numerical derivatives of noisy data, which can be a critical step in developing dynamic models or designing control. There are seven different families of methods implemented in this repository:
2828

29-
1. convolutional smoothing followed by finite difference calculation
30-
2. polynomial fit methods
31-
3. basis function fit methods
32-
4. iterated finite differencing
29+
1. prefiltering followed by finite difference calculation
30+
2. iterated finite differencing
31+
3. polynomial fit methods
32+
4. basis function fit methods
3333
5. total variation regularization of a finite difference derivative
3434
6. generalized Kalman smoothing
3535
7. local approximation with linear model

docs/source/smooth_finite_difference.rst

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,11 @@ smooth_finite_difference
22
========================
33

44
.. automodule:: pynumdiff.smooth_finite_difference
5-
:members:
5+
:no-members:
6+
7+
.. autofunction:: pynumdiff.smooth_finite_difference.kerneldiff
8+
.. autofunction:: pynumdiff.smooth_finite_difference.butterdiff
9+
.. autofunction:: pynumdiff.smooth_finite_difference.meandiff
10+
.. autofunction:: pynumdiff.smooth_finite_difference.mediandiff
11+
.. autofunction:: pynumdiff.smooth_finite_difference.gaussiandiff
12+
.. autofunction:: pynumdiff.smooth_finite_difference.friedrichsdiff

examples/1_basic_tutorial.ipynb

Lines changed: 127 additions & 257 deletions
Large diffs are not rendered by default.

examples/2a_optimizing_parameters_with_dxdt_known.ipynb

Lines changed: 64 additions & 185 deletions
Large diffs are not rendered by default.

examples/2b_optimizing_parameters_with_dxdt_unknown.ipynb

Lines changed: 65 additions & 187 deletions
Large diffs are not rendered by default.

examples/4_performance_analysis.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,13 @@
8787
"\t\t\t(splinediff, 'SplineDiff'),\n",
8888
"\t\t\t(polydiff, 'PolyDiff'),\n",
8989
"\t\t\t(savgoldiff, 'SavGolDiff'),\n",
90-
"\t\t (spectraldiff, 'SpectralDiff'),\n",
90+
"\t\t\t(spectraldiff, 'SpectralDiff'),\n",
9191
"\t\t\t(rbfdiff, 'RBF'),\n",
9292
"\t\t\t(finitediff, 'IteratedFD'), # skip first_order, because it's not going to be the best\n",
9393
"\t\t\t(tvrdiff, 'TVR'),\n",
9494
"\t\t\t(smooth_acceleration, 'SmoothAccelTVR'), # skip in plotting?\n",
9595
"\t\t\t(rtsdiff, 'RTS'),\n",
96-
"\t\t (robustdiff, 'RobustDiff')]\n",
96+
"\t\t\t(robustdiff, 'RobustDiff')]\n",
9797
"sims = [(pi_cruise_control, 'Cruise Control'),\n",
9898
"\t\t(sine, 'Sum of Sines'),\n",
9999
"\t\t(triangle, 'Triangles'),\n",

pynumdiff/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from .linear_model import lineardiff
1414

1515
from .finite_difference import finitediff, first_order, second_order, fourth_order
16-
from .smooth_finite_difference import meandiff, mediandiff, gaussiandiff, friedrichsdiff, butterdiff
16+
from .smooth_finite_difference import kerneldiff, meandiff, mediandiff, gaussiandiff, friedrichsdiff, butterdiff
1717
from .polynomial_fit import splinediff, polydiff, savgoldiff
1818
from .basis_fit import spectraldiff, rbfdiff
1919
from .total_variation_regularization import iterative_velocity

pynumdiff/finite_difference/_finite_difference.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ def finitediff(x, dt, num_iterations, order):
6565

6666

6767
def first_order(x, dt, params=None, options={}, num_iterations=1):
68-
"""First-order difference method
68+
"""First-order difference method\n
69+
**Deprecated**, prefer :code:`finitediff` with order 1 instead.
6970
7071
:param np.array[float] x: data to differentiate
7172
:param float dt: step size
@@ -85,11 +86,13 @@ def first_order(x, dt, params=None, options={}, num_iterations=1):
8586
warn("`params` and `options` parameters will be removed in a future version. Use `num_iterations` instead.", DeprecationWarning)
8687
num_iterations = params[0] if isinstance(params, list) else params
8788

89+
warn("`first_order` is deprecated. Call `finitediff` with order 1 instead.", DeprecationWarning)
8890
return finitediff(x, dt, num_iterations, 1)
8991

9092

9193
def second_order(x, dt, num_iterations=1):
92-
"""Second-order centered difference method, with special endpoint formulas.
94+
"""Second-order centered difference method, with special endpoint formulas.\n
95+
**Deprecated**, prefer :code:`finitediff` with order 2 instead.
9396
9497
:param np.array[float] x: data to differentiate
9598
:param float dt: step size
@@ -100,11 +103,13 @@ def second_order(x, dt, num_iterations=1):
100103
- **x_hat** -- original x if :code:`num_iterations=1`, else smoothed x that yielded dxdt_hat
101104
- **dxdt_hat** -- estimated derivative of x
102105
"""
106+
warn("`second_order` is deprecated. Call `finitediff` with order 2 instead.", DeprecationWarning)
103107
return finitediff(x, dt, num_iterations, 2)
104108

105109

106110
def fourth_order(x, dt, num_iterations=1):
107-
"""Fourth-order centered difference method, with special endpoint formulas.
111+
"""Fourth-order centered difference method, with special endpoint formulas.\n
112+
**Deprecated**, prefer :code:`finitediff` with order 4 instead.
108113
109114
:param np.array[float] x: data to differentiate
110115
:param float dt: step size
@@ -115,4 +120,5 @@ def fourth_order(x, dt, num_iterations=1):
115120
- **x_hat** -- original x if :code:`num_iterations=1`, else smoothed x that yielded dxdt_hat
116121
- **dxdt_hat** -- estimated derivative of x
117122
"""
123+
warn("`fourth_order` is deprecated. Call `finitediff` with order 4 instead.", DeprecationWarning)
118124
return finitediff(x, dt, num_iterations, 4)

pynumdiff/kalman_smooth/_kalman_smooth.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ def rtsdiff(x, _t, order, qr_ratio, forwardbackward):
170170

171171

172172
def constant_velocity(x, dt, params=None, options=None, r=None, q=None, forwardbackward=True):
173-
"""Run a forward-backward constant velocity RTS Kalman smoother to estimate the derivative.
173+
"""Run a forward-backward constant velocity RTS Kalman smoother to estimate the derivative.\n
174+
**Deprecated**, prefer :code:`rtsdiff` with order 1 instead.
174175
175176
:param np.array[float] x: data series to differentiate
176177
:param float dt: step size
@@ -195,11 +196,13 @@ def constant_velocity(x, dt, params=None, options=None, r=None, q=None, forwardb
195196
elif r == None or q == None:
196197
raise ValueError("`q` and `r` must be given.")
197198

199+
warn("`constant_velocity` is deprecated. Call `rtsdiff` with order 1 instead.", DeprecationWarning)
198200
return rtsdiff(x, dt, 1, q/r, forwardbackward)
199201

200202

201203
def constant_acceleration(x, dt, params=None, options=None, r=None, q=None, forwardbackward=True):
202-
"""Run a forward-backward constant acceleration RTS Kalman smoother to estimate the derivative.
204+
"""Run a forward-backward constant acceleration RTS Kalman smoother to estimate the derivative.\n
205+
**Deprecated**, prefer :code:`rtsdiff` with order 2 instead.
203206
204207
:param np.array[float] x: data series to differentiate
205208
:param float dt: step size
@@ -224,11 +227,13 @@ def constant_acceleration(x, dt, params=None, options=None, r=None, q=None, forw
224227
elif r == None or q == None:
225228
raise ValueError("`q` and `r` must be given.")
226229

230+
warn("`constant_acceleration` is deprecated. Call `rtsdiff` with order 2 instead.", DeprecationWarning)
227231
return rtsdiff(x, dt, 2, q/r, forwardbackward)
228232

229233

230234
def constant_jerk(x, dt, params=None, options=None, r=None, q=None, forwardbackward=True):
231-
"""Run a forward-backward constant jerk RTS Kalman smoother to estimate the derivative.
235+
"""Run a forward-backward constant jerk RTS Kalman smoother to estimate the derivative.\n
236+
**Deprecated**, prefer :code:`rtsdiff` with order 3 instead.
232237
233238
:param np.array[float] x: data series to differentiate
234239
:param float dt: step size
@@ -253,6 +258,7 @@ def constant_jerk(x, dt, params=None, options=None, r=None, q=None, forwardbackw
253258
elif r == None or q == None:
254259
raise ValueError("`q` and `r` must be given.")
255260

261+
warn("`constant_jerk` is deprecated. Call `rtsdiff` with order 3 instead.", DeprecationWarning)
256262
return rtsdiff(x, dt, 3, q/r, forwardbackward)
257263

258264

pynumdiff/optimize/_optimize.py

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from ..utils import evaluate
1212
from ..finite_difference import finitediff, first_order, second_order, fourth_order
13-
from ..smooth_finite_difference import mediandiff, meandiff, gaussiandiff, friedrichsdiff, butterdiff
13+
from ..smooth_finite_difference import kerneldiff, mediandiff, meandiff, gaussiandiff, friedrichsdiff, butterdiff
1414
from ..polynomial_fit import polydiff, savgoldiff, splinediff
1515
from ..basis_fit import spectraldiff, rbfdiff
1616
from ..total_variation_regularization import tvrdiff, velocity, acceleration, jerk, iterative_velocity, smooth_acceleration, jerk_sliding
@@ -19,10 +19,25 @@
1919

2020
# Map from method -> (search_space, bounds_low_hi)
2121
method_params_and_bounds = {
22-
meandiff: ({'window_size': [5, 15, 30, 50],
22+
kerneldiff: ({'kernel': {'mean', 'median', 'gaussian', 'friedrichs'},
23+
'window_size': [5, 15, 30, 50],
24+
'num_iterations': [1, 5, 10]},
25+
{'window_size': (1, 1e6),
26+
'num_iterations': (1, 100)}),
27+
meandiff: ({'window_size': [5, 15, 30, 50], # Deprecated method
2328
'num_iterations': [1, 5, 10]},
2429
{'window_size': (1, 1e6),
2530
'num_iterations': (1, 100)}),
31+
butterdiff: ({'filter_order': set(i for i in range(1,11)), # categorical to save us from doing double work by guessing between orders
32+
'cutoff_freq': [0.0001, 0.001, 0.005, 0.01, 0.1, 0.5],
33+
'num_iterations': [1, 5, 10]},
34+
{'cutoff_freq': (1e-4, 1-1e-2),
35+
'num_iterations': (1, 1000)}),
36+
finitediff: ({'num_iterations': [5, 10, 30, 50],
37+
'order': {2, 4}}, # order is categorical here, because it can't be 3
38+
{'num_iterations': (1, 1000)}),
39+
first_order: ({'num_iterations': [5, 10, 30, 50]}, # Separated because optimizing over this one is rare due to shifted answer
40+
{'num_iterations': (1, 1000)}),
2641
polydiff: ({'step_size': [1, 2, 5],
2742
'kernel': {'friedrichs', 'gaussian'}, # categorical
2843
'degree': [2, 3, 5, 7],
@@ -49,26 +64,16 @@
4964
'lmbd': [1e-3, 1e-2, 1e-1]},
5065
{'sigma': (1e-3, 1e3),
5166
'lmbd': (1e-4, 0.5)}),
52-
finitediff: ({'num_iterations': [5, 10, 30, 50],
53-
'order': {2, 4}}, # order is categorical here, because it can't be 3
54-
{'num_iterations': (1, 1000)}),
55-
first_order: ({'num_iterations': [5, 10, 30, 50]},
56-
{'num_iterations': (1, 1000)}),
57-
butterdiff: ({'filter_order': set(i for i in range(1,11)), # categorical to save us from doing double work by guessing between orders
58-
'cutoff_freq': [0.0001, 0.001, 0.005, 0.01, 0.1, 0.5],
59-
'num_iterations': [1, 5, 10]},
60-
{'cutoff_freq': (1e-4, 1-1e-2),
61-
'num_iterations': (1, 1000)}),
6267
tvrdiff: ({'gamma': [1e-2, 1e-1, 1, 10, 100, 1000],
6368
'order': {1, 2, 3}}, # warning: order 1 hacks the loss function when tvgamma is used, tends to win but is usually suboptimal choice in terms of true RMSE
6469
{'gamma': (1e-4, 1e7)}),
65-
velocity: ({'gamma': [1e-2, 1e-1, 1, 10, 100, 1000]},
70+
velocity: ({'gamma': [1e-2, 1e-1, 1, 10, 100, 1000]}, # Deprecated method
6671
{'gamma': (1e-4, 1e7)}),
67-
iterative_velocity: ({'num_iterations': [1, 5, 10],
68-
'gamma': [1e-2, 1e-1, 1, 10, 100, 1000],
69-
'scale': 'small'},
70-
{'num_iterations': (1, 100), # gets expensive with more iterations
71-
'gamma': (1e-4, 1e7)}),
72+
iterative_velocity: ({'scale': 'small', # Rare to optimize this one, because it's longer-running than convex version
73+
'num_iterations': [1, 5, 10],
74+
'gamma': [1e-2, 1e-1, 1, 10, 100, 1000]},
75+
{'num_iterations': (1, 100), # gets expensive with more iterations
76+
'gamma': (1e-4, 1e7)}),
7277
smooth_acceleration: ({'gamma': [1e-2, 1e-1, 1, 10, 100, 1000],
7378
'window_size': [3, 10, 30, 50, 90, 130]},
7479
{'gamma': (1e-4, 1e7),
@@ -77,7 +82,7 @@
7782
'order': {1, 2, 3}, # for this few options, the optimization works better if this is categorical
7883
'qr_ratio': [10**k for k in range(-9, 10, 2)] + [1e12, 1e16]},
7984
{'qr_ratio': [1e-10, 1e20]}), # qr_ratio is usually >>1
80-
constant_velocity: ({'q': [1e-8, 1e-4, 1e-1, 1e1, 1e4, 1e8],
85+
constant_velocity: ({'q': [1e-8, 1e-4, 1e-1, 1e1, 1e4, 1e8], # Deprecated method
8186
'r': [1e-8, 1e-4, 1e-1, 1e1, 1e4, 1e8],
8287
'forwardbackward': {True, False}},
8388
{'q': (1e-10, 1e10),
@@ -95,14 +100,14 @@
95100
'gamma': (1e-3, 1000),
96101
'window_size': (15, 1000)})
97102
} # Methods with nonunique parameter sets are aliased in the dictionary below
98-
for method in [second_order, fourth_order]:
103+
for method in [second_order, fourth_order]: # Deprecated, redundant methods
99104
method_params_and_bounds[method] = method_params_and_bounds[first_order]
100-
for method in [mediandiff, gaussiandiff, friedrichsdiff]:
105+
for method in [mediandiff, gaussiandiff, friedrichsdiff]: # Deprecated methods
101106
method_params_and_bounds[method] = method_params_and_bounds[meandiff]
102-
for method in [acceleration, jerk]:
107+
for method in [acceleration, jerk]: # Deprecated, redundant methods
103108
method_params_and_bounds[method] = method_params_and_bounds[velocity]
104109
method_params_and_bounds[jerk_sliding] = method_params_and_bounds[smooth_acceleration]
105-
for method in [constant_acceleration, constant_jerk]:
110+
for method in [constant_acceleration, constant_jerk]: # Deprecated, redundant methods
106111
method_params_and_bounds[method] = method_params_and_bounds[constant_velocity]
107112

108113

0 commit comments

Comments
 (0)