A sparse matrix implementation of Whittaker-Eilers smoothing and interpolation
Project description
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 in addition to it being super speedy. The API is almost identical.
pip install whittaker-eilers
Usage
To start smoothing and interpolating data, create a reusable WhittakerSmoother class. You'll only need to recreate this class if the length or sampling rate of your data changes.
Equally spaced data
This is the fastest smoothing option. It smooths equally spaced y measurements using two tunable parameters, lambda
(2e4) and the smoother order
(2). The larger the lambda, the smoother the data.
from whittaker_eilers import WhittakerSmoother
data_to_smooth = [1.1, 1.9, 3.1, 3.91, 5.0, 6.02, 7.01, 7.7, 9.0, 10.0]
whittaker_smoother = WhittakerSmoother(lmbda=2e4, order=2, data_length = len(data_to_smooth))
smoothed_data = whittaker_smoother.smooth(data_to_smooth)
print("Smoothed data: {}".format(smoothed_data))
Non-equally spaced data
If you wish to smooth unequally spaced data, you need to provide an x_input
with the sample times/positions.
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]
whittaker_smoother = WhittakerSmoother(
lmbda=2e4, order=2, data_length=len(data_to_smooth), x_input=x_input
)
smoothed_data = whittaker_smoother.smooth(data_to_smooth)
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.
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,
)
smoothed_data = whittaker_smoother.smooth(data_to_smooth)
print("Smoothed and interpolated weighted data: {}".format(smoothed_data))
Smoothing with cross validation
With this package, you can also calculate the cross validation error alongside the smoothed series. This shouldn't really be used in production where speed is necessary though!
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]
whittaker_smoother = WhittakerSmoother(
lmbda=2e4, order=2, data_length=len(data_to_smooth), x_input=x_input
)
smoothed_data_with_cross_validation = whittaker_smoother.smooth_and_cross_validate(
data_to_smooth
)
print(
"Error :{}".format(smoothed_data_with_cross_validation.get_cross_validation_error())
)
print("Smoothed :{}".format(smoothed_data_with_cross_validation.get_smoothed()))
Automatic smoothing
Smoothing data requires a choice of Lambda. This can be done using visual inspection or by finding the lambda
which results in the lowest cross validation error. The smooth_optimal
function runs the smoother for a variety of lambdas and returns the results with the ability to retrieve the optimal one.
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]
whittaker_smoother = WhittakerSmoother(
lmbda=2e4, order=2, data_length=len(data_to_smooth), x_input=x_input
)
optimal_smooth = whittaker_smoother.smooth_optimal(data_to_smooth)
print("Optimal lambda: {}".format(optimal_smooth.get_optimal().get_lambda()))
print("Optimally smoothed data: {}".format(optimal_smooth.get_optimal().get_smoothed()))
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 repository. Here's an image of some smoothed data from an example:
Other methods
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)
Further Reading
If you'd like to see a more detailed run through of the library, check out this Medium post. Within it, I run through examples and benchmarks against other smoothing methods.
Future Features
- Scatter plot smoothing
- Generic typing
References
The algorithm implemented here mirrors a 2003 implementation by Paul H. C. Eilers in Matlab. I've included scripts and data from the original paper in the tests for this package. The original paper and code can be found here:
A Perfect Smoother Paul H. C. Eilers Analytical Chemistry 2003 75 (14), 3631-3636 DOI: 10.1021/ac034173t
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Hashes for whittaker_eilers-0.1.3-cp37-abi3-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6b7d3200d30d00964210cdae9dc0be532bd2c27f246205f6fb0563b4a75dbe3b |
|
MD5 | fb5aaeb1743ba39b9faaaed72031e936 |
|
BLAKE2b-256 | f57b5db3c1857a662b51c41e34c5be2432e839055ca68f50815420206084cb22 |
Hashes for whittaker_eilers-0.1.3-cp37-abi3-win32.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | fcf9939b3a3abc0304aff7ac0892c6ca89efb6e50b932e56b53f6e616dc5e77f |
|
MD5 | 4d6269107806a05329f9fd2497325276 |
|
BLAKE2b-256 | 03ba43b71b203c9aaad5398578f340efbb7a3bcdf85d240231b5216259fefc44 |
Hashes for whittaker_eilers-0.1.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 643a14e11c7826fc773b008da896a2d794d85658b3a5fd2f3e40adaac0a782e6 |
|
MD5 | d7a22176e07d39337a22a86629df2543 |
|
BLAKE2b-256 | e2256bdf381892da33834edd9bd05bdc04b311a7bf2424791915941e9c81b855 |
Hashes for whittaker_eilers-0.1.3-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 16ff77ba4af65241e4e0cb3bda1e535592bcd2bdd882fd96c304995793673bc0 |
|
MD5 | 705aed5f9bcbf80abd52e59a17bd5423 |
|
BLAKE2b-256 | 830d52754062d0edf6489e00c8ed1b652d7b8f60b35f477adc2f941cc99398f7 |
Hashes for whittaker_eilers-0.1.3-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 954a4e2306123b21fc69d153c04af1d88c764309adacad5981e110271a9f4513 |
|
MD5 | 8d719cfa7c063857195ea59e24ba493c |
|
BLAKE2b-256 | b5787269e5e109fee0200af89af79a9d98b9584aa97f7f8cbd0d75d576568e6f |
Hashes for whittaker_eilers-0.1.3-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | d8ad76d956707278e690cc1f5d1fbe52d3d37dcb2469cb3100b09cc2b181937b |
|
MD5 | 44868a5f9db8e31f7a33c2dd4e8fef2a |
|
BLAKE2b-256 | 9b33fcd6fe5b6c3797336aea76b16660eda7ac3cb6b6a0853949bd97252a9e4f |
Hashes for whittaker_eilers-0.1.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f5ccd060c8d7cf517164c18d96675ab5853b2c692db6c03c4ab5f7cadde31be6 |
|
MD5 | abc6b09db2416545eba9d58d4195f2bf |
|
BLAKE2b-256 | a6b7dadeced6ee3e1ffaec91998ab30f8f86baaa212c1e7a07a82f6d0b020423 |
Hashes for whittaker_eilers-0.1.3-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | ea511aff897312e6a66b7ae855db31b3170a4c1966d75bb30f50d07f4a5c4a05 |
|
MD5 | 91572fea15451a404496802afbb4e90e |
|
BLAKE2b-256 | 7473b139461fc82ea417d832d465415e00989cb8962679fb92c4cc61a9b79d13 |
Hashes for whittaker_eilers-0.1.3-cp37-abi3-macosx_11_0_arm64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 10f8a2cfe46d86b3050a6524d824bc3c7cb86addda0618be3cca43d73f2349b8 |
|
MD5 | b19021efd233636c154e9e83b9176f76 |
|
BLAKE2b-256 | 88ca7d36a733c71edf2e6af4dd48361ff1d28fc4ab803f2280ecf1b95b75b2d9 |
Hashes for whittaker_eilers-0.1.3-cp37-abi3-macosx_10_12_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 179a8e9ee9859874499b4ff8dcb8ce2a0f89a6fbedf9988603d89b8c8df22200 |
|
MD5 | f17d296c8cbd7cc6fc62073dd03a0906 |
|
BLAKE2b-256 | 1c0bfdc80a083d9e00297dc1403ae880a7a5a6a40af9aab9716ab6fe3427c5cc |