From bb621e3bd281060266902dca10bf8fe9f661d0eb Mon Sep 17 00:00:00 2001 From: Andrew Bowell <49959927+AnBowell@users.noreply.github.com> Date: Thu, 12 Oct 2023 07:03:15 +0100 Subject: [PATCH] ci: :construction_worker: GitHub actions added to build out Python package --- .github/workflows/CI.yml | Bin 0 -> 6190 bytes whittaker-eilers-py/README.md | 52 ++- .../examples/smooth_and_interpolate.py | 28 ++ whittaker-eilers-py/pyproject.toml | 1 + whittaker-eilers-py/tests/python/test.py | 353 ------------------ whittaker-eilers-py/whittaker_eilers.pyi | 6 +- 6 files changed, 72 insertions(+), 368 deletions(-) create mode 100644 .github/workflows/CI.yml delete mode 100644 whittaker-eilers-py/tests/python/test.py diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000000000000000000000000000000000000..fbac4a76eced4debbd6d0ea5b788eca88994b080 GIT binary patch literal 6190 zcmeHLZEF)j5T4J1|KW&2wRnxCrD{J}iyuU^p;$zUge1MZ*yIxLlD;7Rb@h36vbo*8 zHqlyJis8uRZg+NeUZ2~UpFbW*Bp;+JJ<0LZ#(!TDJn4HwCNh?xbTF3Umq`Qfi5!8V zDd)Hk%*X^YJy1k)BI~jy8~8ny`*Kf|{}3}18DX8Se}eZ6Bk7dJQbrgr^9*;7rG?!h zNY#ThUGQn*Eru+SoElxm7;nh2kvPU(waTDl3@Of~D!Z7^z+nhUso?;6s}#Jam>po< zHaPCe8#BZ4A!fGC8|55f=N$VLBOGlSE2WUJ3l4cOONtmj+KmHmp04CA zGeXa&Sj!puF9D~cnQgv+rs=Kf8x1FN=14_7)${a)+LN)-#E-lu80{MgRUg+r)Xzp> z2VV5;PR<&QjKy$IwXoWleow%QS{#D%xop8YTe2yPOMT~416O7&W#{-lK#V^#lsV%3 z1>*e7yp3SRmf^w-`aJU#cc$bC=3Sdwi5LxxBaIdA+5)xpLDlS^;C>8iF&kfE{|%2j zIW6Ks{26>)3VQeHR9 zUO_fyDUpRaoZ#w%o9lnO*0oj*y6j<}>eTlZiDJ)=)N=hoUW>J4R=N@MP`=^vV~rS6 zP(|_`*F}<31Etd(is23B5hJEyVt}4xUeMFgG-LV1QAT$PE44w*h@vN%%U#U>E$&&{ zy8k(%u7w>G$<(9FKw?eVqjsfAc@CY3Z<_toTE8TrRl+zpfKJ3KBFmpeLYOyZBBm0}iN(x(#>7<-CCr^AhTe4y4L$llq9MN@JZ~;W!h-VVQP4j#`X|LD zCeFviFv^#>wZyHJ{ehW|HPf$?iF zm{vbW=EO8#I!YK;S+`qJg^1^W*XL{F+WPL+IDVDuXNVhv`#2L9)vz0TSIr~Vd|JD* zX4X0|myhNo-jzpQ7jey;$=jx%vod|o(Oa;cxvH$l_P(x|cm9zgpu+ zacbdP;rr`5HE1Q7-g5OD#(WK^(KOa!&y<}wc7@r$sZBeqF2YH)iJs!Z{;;c-CB+Pw3dkw_Cwbk`km6c%lko$j`=;dGWNM&L^nTN v>xJl-!qzGJMeH-M{$v+byNvAGX?H0{hp~rV1^eY^cw)AYzJvKy)35jioQ`jN literal 0 HcmV?d00001 diff --git a/whittaker-eilers-py/README.md b/whittaker-eilers-py/README.md index cf41fcf..e215591 100644 --- a/whittaker-eilers-py/README.md +++ b/whittaker-eilers-py/README.md @@ -1,5 +1,5 @@ # Whittaker-Eilers Smoothing and Interpolation -**The Whittaker-Eilers smoother is the perfect smoother.** It offers extremely quick, efficient smoothing with built-in interpolation via weights on each measurement. This package provides a sparse-matrix implementation for additional speed and memory efficiency and can handle both equally and unequally spaced measurements. This package was originally written in Rust, so additional examples, tests, and benchmarks are also available. The API is almost identical. +**The Whittaker-Eilers smoother is the perfect smoother.** It offers extremely quick, efficient smoothing with built-in interpolation via weights on each measurement. This package provides a sparse-matrix implementation for additional speed and memory efficiency and can handle both equally and unequally spaced measurements. This package was originally written in Rust so additional examples, tests, and benchmarks are also available in addition to it being super speedy. The API is almost identical. --- @@ -47,27 +47,55 @@ print("Smoothed non-equally spaced data: {}".format(smoothed_data)) ### Weighted data & Interpolation Each measurement can then be weighted to trust some measurements more than others. Setting `weights` to 0 for measurements will lead to interpolation. -```rust -use whittaker_eilers::WhittakerSmoother; +```python +from whittaker_eilers import WhittakerSmoother -let x_input = vec![1.1, 1.9, 3.1, 3.91, 5.0, 6.02, 7.01, 7.7, 9.0, 10.0]; -let data_to_smooth = vec![1.1, 1.9, 3.1, 3.91, 5.0, 6.02, 7.01, 7.7, 9.0, 10.0]; -let mut weights = vec![1.0; x_input.len()]; -weights[5] = 0.0; +x_input = [1.1, 1.9, 3.1, 3.91, 5.0, 6.02, 7.01, 7.7, 9.0, 10.0] +data_to_smooth = [1.1, 1.9, 3.1, 3.91, 5.0, 6.02, 7.01, 7.7, 9.0, 10.0] +weights = [1.0] * len(x_input) +weights[5] = 0.0 -let whittaker_smoother = - WhittakerSmoother::new(2e4, 2, data_to_smooth.len(), Some(&x_input), Some(&weights)) - .unwrap(); +whittaker_smoother = WhittakerSmoother( + lmbda=2e4, + order=2, + data_length=len(data_to_smooth), + x_input=x_input, + weights=weights, +) -let smoothed_data = whittaker_smoother.smooth(&data_to_smooth).unwrap(); +smoothed_data = whittaker_smoother.smooth(data_to_smooth) -println!("Smoothed data: {:?}", smoothed_data); +print("Smoothed and interpolated weighted data: {}".format(smoothed_data)) ``` You can use these methods in combination with each other for instance, interpolating measurements without providing an x input. For more advanced examples of usage take a look at the examples, tests, and benches in the [Github](https://github.com/AnBowell/whittaker-eilers) repository. Here's an image of some smoothed data from an example: Time-series smoothed by Whittaker-Eilers method +### Other methods +```python +from whittaker_eilers import WhittakerSmoother +x_input = [1.1, 1.9, 3.1, 3.91, 5.0, 6.02, 7.01, 7.7, 9.0, 10.0] +data_to_smooth = [1.1, 1.9, 3.1, 3.91, 5.0, 6.02, 7.01, 7.7, 9.0, 10.0] +weights = [1.0] * len(x_input) +weights[5] = 0.0 + +whittaker_smoother = WhittakerSmoother( + lmbda=2e4, + order=2, + data_length=len(data_to_smooth), + x_input=x_input, + weights=weights, +) + +whittaker_smoother.get_order() +whittaker_smoother.get_lambda() +whittaker_smoother.get_data_length() +whittaker_smoother.update_weights([0.5] * len(x_input)) +whittaker_smoother.update_order(3) +whittaker_smoother.update_lambda(4321.0) +``` + ## Future Features - Cross validation options to find optimal lambda. - Scatter plot smoothing diff --git a/whittaker-eilers-py/examples/smooth_and_interpolate.py b/whittaker-eilers-py/examples/smooth_and_interpolate.py index 1283b90..31ff542 100644 --- a/whittaker-eilers-py/examples/smooth_and_interpolate.py +++ b/whittaker-eilers-py/examples/smooth_and_interpolate.py @@ -1,4 +1,5 @@ from whittaker_eilers import WhittakerSmoother +from time import perf_counter_ns def smooth_equally_spaced(): @@ -45,7 +46,34 @@ def smoothed_weighted_and_interpolation(): print("Smoothed and interpolated weighted data: {}".format(smoothed_data)) +def update_smoother(): + x_input = [1.1, 1.9, 3.1, 3.91, 5.0, 6.02, 7.01, 7.7, 9.0, 10.0] + data_to_smooth = [1.1, 1.9, 3.1, 3.91, 5.0, 6.02, 7.01, 7.7, 9.0, 10.0] + weights = [1.0] * len(x_input) + weights[5] = 0.0 + + whittaker_smoother = WhittakerSmoother( + lmbda=2e4, + order=2, + data_length=len(data_to_smooth), + x_input=x_input, + weights=weights, + ) + + whittaker_smoother.update_lambda(3e4) + whittaker_smoother.update_order(3) + whittaker_smoother.update_weights([0.5] * len(x_input)) + + smoothed_data = whittaker_smoother.smooth(data_to_smooth) + + print("Updated & Smoothed data: {}".format(smoothed_data)) + + if __name__ == "__main__": + start_time = perf_counter_ns() smooth_equally_spaced() smoothed_non_equally_spaced_data() smoothed_weighted_and_interpolation() + update_smoother() + end_time = perf_counter_ns() + print("Smoothing tests took : {} ms".format((end_time - start_time) / 1e6)) diff --git a/whittaker-eilers-py/pyproject.toml b/whittaker-eilers-py/pyproject.toml index 477fabb..acd6845 100644 --- a/whittaker-eilers-py/pyproject.toml +++ b/whittaker-eilers-py/pyproject.toml @@ -22,3 +22,4 @@ authors = [{ name = "Andrew Bowell" }] readme = "README.md" [project.urls] repository = "https://github.com/AnBowell/whittaker-eilers/tree/main/whittaker-eilers-py" +documentation = "https://github.com/AnBowell/whittaker-eilers/tree/main/whittaker-eilers-py" diff --git a/whittaker-eilers-py/tests/python/test.py b/whittaker-eilers-py/tests/python/test.py deleted file mode 100644 index f214fad..0000000 --- a/whittaker-eilers-py/tests/python/test.py +++ /dev/null @@ -1,353 +0,0 @@ -from whittaker_eilers import WhittakerSmoother -from time import perf_counter_ns -import numpy as np -from EOkit.smoothers.whittaker import single_whittaker -import polars - - -def main(): - x = [i for i in range(len(WOOD_DATA))] - weights = [i for i in range(len(WOOD_DATA))] - start = perf_counter_ns() - - smoother = WhittakerSmoother(lmbda=2e4, order=2, data_length=len(WOOD_DATA)) - # smoother.update_weights([12.0]) - smoothed_data = smoother.smooth(WOOD_DATA) - end = perf_counter_ns() - - print("New package took {:.5f} microseconds".format((end - start) / 1e3)) - x = np.array(x).astype(float) - wood_data = np.array(WOOD_DATA).astype(float) - weights = np.array(weights).astype(float) - - start = perf_counter_ns() - eo_kit_smoothed_data = single_whittaker(x, wood_data, weights, 2e4, 2) - end = perf_counter_ns() - - print("EO kit took {:.5f} microseconds".format((end - start) / 1e3)) - - -WOOD_DATA = [ - 106.0, - 111.0, - 111.0, - 107.0, - 105.0, - 107.0, - 110.0, - 108.0, - 111.0, - 119.0, - 117.0, - 107.0, - 105.0, - 107.0, - 109.0, - 105.0, - 104.0, - 102.0, - 108.0, - 113.0, - 113.0, - 107.0, - 103.0, - 103.0, - 98.0, - 102.0, - 103.0, - 104.0, - 105.0, - 105.0, - 105.0, - 101.0, - 103.0, - 107.0, - 109.0, - 104.0, - 100.0, - 103.0, - 100.0, - 105.0, - 102.0, - 105.0, - 106.0, - 107.0, - 104.0, - 107.0, - 109.0, - 108.0, - 111.0, - 107.0, - 107.0, - 106.0, - 107.0, - 102.0, - 102.0, - 101.0, - 103.0, - 103.0, - 103.0, - 100.0, - 101.0, - 101.0, - 100.0, - 102.0, - 101.0, - 96.0, - 96.0, - 98.0, - 104.0, - 107.0, - 107.0, - 102.0, - 105.0, - 101.0, - 105.0, - 110.0, - 111.0, - 111.0, - 100.0, - 102.0, - 102.0, - 107.0, - 112.0, - 114.0, - 113.0, - 108.0, - 106.0, - 103.0, - 103.0, - 101.0, - 103.0, - 106.0, - 107.0, - 106.0, - 107.0, - 107.0, - 104.0, - 111.0, - 117.0, - 118.0, - 115.0, - 107.0, - 110.0, - 117.0, - 121.0, - 122.0, - 123.0, - 119.0, - 117.0, - 118.0, - 115.0, - 111.0, - 108.0, - 107.0, - 105.0, - 105.0, - 105.0, - 103.0, - 105.0, - 107.0, - 109.0, - 110.0, - 111.0, - 108.0, - 107.0, - 106.0, - 108.0, - 107.0, - 105.0, - 102.0, - 101.0, - 102.0, - 101.0, - 97.0, - 100.0, - 105.0, - 108.0, - 108.0, - 105.0, - 103.0, - 103.0, - 100.0, - 103.0, - 106.0, - 107.0, - 97.0, - 98.0, - 100.0, - 101.0, - 97.0, - 99.0, - 101.0, - 104.0, - 107.0, - 109.0, - 111.0, - 109.0, - 103.0, - 105.0, - 102.0, - 108.0, - 113.0, - 113.0, - 108.0, - 107.0, - 102.0, - 106.0, - 106.0, - 106.0, - 103.0, - 97.0, - 103.0, - 107.0, - 102.0, - 107.0, - 111.0, - 110.0, - 107.0, - 103.0, - 99.0, - 97.0, - 99.0, - 100.0, - 99.0, - 100.0, - 99.0, - 100.0, - 99.0, - 99.0, - 98.0, - 100.0, - 102.0, - 102.0, - 106.0, - 112.0, - 113.0, - 109.0, - 107.0, - 105.0, - 97.0, - 105.0, - 110.0, - 113.0, - 108.0, - 101.0, - 95.0, - 99.0, - 100.0, - 97.0, - 92.0, - 98.0, - 101.0, - 103.0, - 101.0, - 92.0, - 95.0, - 91.0, - 86.0, - 86.0, - 87.0, - 93.0, - 97.0, - 95.0, - 91.0, - 86.0, - 87.0, - 88.0, - 88.0, - 89.0, - 87.0, - 90.0, - 88.0, - 87.0, - 89.0, - 90.0, - 90.0, - 87.0, - 86.0, - 88.0, - 83.0, - 85.0, - 85.0, - 87.0, - 91.0, - 93.0, - 96.0, - 95.0, - 89.0, - 89.0, - 85.0, - 88.0, - 89.0, - 92.0, - 95.0, - 91.0, - 87.0, - 83.0, - 83.0, - 82.0, - 81.0, - 81.0, - 80.0, - 81.0, - 82.0, - 80.0, - 76.0, - 72.0, - 73.0, - 75.0, - 77.0, - 75.0, - 80.0, - 81.0, - 81.0, - 81.0, - 81.0, - 81.0, - 84.0, - 86.0, - 87.0, - 88.0, - 86.0, - 84.0, - 82.0, - 80.0, - 79.0, - 82.0, - 82.0, - 76.0, - 81.0, - 83.0, - 82.0, - 81.0, - 75.0, - 78.0, - 78.0, - 78.0, - 79.0, - 82.0, - 82.0, - 84.0, - 82.0, - 77.0, - 77.0, - 77.0, - 75.0, - 77.0, - 73.0, - 75.0, - 76.0, - 80.0, - 77.0, - 68.0, - 71.0, - 71.0, - 68.0, - 67.0, - 69.0, - 72.0, - 82.0, -] -if __name__ == "__main__": - main() diff --git a/whittaker-eilers-py/whittaker_eilers.pyi b/whittaker-eilers-py/whittaker_eilers.pyi index 3555f7a..95425a5 100644 --- a/whittaker-eilers-py/whittaker_eilers.pyi +++ b/whittaker-eilers-py/whittaker_eilers.pyi @@ -14,9 +14,9 @@ class WhittakerSmoother: Parameters ---------- - lambda : Controls the smoothing strength, the larger, the smoother. - order : The order of the filter. - data_length : The length of the data which is to be smoothed. + lambda : Controls the smoothing strength, the larger, the smoother. Must be positive. + order : The order of the filter. Must be positive. + data_length : The length of the data which is to be smoothed. Must be positive. x_input : The time/position at which the y measurement was taken. Used to smooth unequally spaced data. Must be monotonically increasing. weights : The weight of each y measurement."""