tsdownsample

repository·main·Indexed 42 days ago

https://github.com/predict-idlab/tsdownsample

A high-performance time series downsampling library written in Rust with Python bindings. It provides algorithms like LTTB (Largest Triangle Three Buckets), M4, and Min-Max to reduce the number of points in large datasets while preserving key visual features. Version 0.1.0 supports parallel execution via the TSDOWNSAMPLE_MAX_THREADS environment variable and includes specialized classes for handling NaN values in y-axis data.

Tokens
7.6K
Snippets
29
Records
40
Agent score
52%

What's inside tsdownsample

  1. Use the tsdownsample Python module

    main

    The tsdownsample module provides high-performance time series downsampling algorithms implemented in Rust. It is organized into submodules based on the algorithm used (minmax, m4, lttb, minmaxlttb) and the execution mode (sequential or parallel).

    Each algorithm submodule contains further submodules for sequential and parallel execution. Functions within these submodules allow for downsampling either with or without explicit x-axis data (assuming constant sampling rates) and can handle NaN values in specific versions.

    import tsdownsample
    
    # Accessing algorithms
    minmax = tsdownsample.minmax
    m4 = tsdownsample.m4
    lttb = tsdownsample.lttb
    minmaxlttb = tsdownsample.minmaxlttb
  2. Understand MinMaxLTTB parameters

    main

    The MinMaxLTTB algorithm uses the following parameters:

    • n_out: The target number of points to return in the downsampled output.
    • minmax_ratio: A threshold used to decide if a preliminary min-max aggregation step is needed. If input_length / n_out > minmax_ratio, the algorithm first performs a min-max aggregation to reduce the data size before applying the standard LTTB (Largest Triangle Three Buckets) algorithm. This improves performance on very large datasets.
  3. Configure parallel execution and thread limits

    main

    All downsamplers support a parallel keyword argument to enable multi-threading.

    To control the maximum number of threads used by the Rust backend, set the TSDOWNSAMPLE_MAX_THREADS environment variable.

    import os
    os.environ["TSDOWNSAMPLE_MAX_THREADS"] = "4"
  4. Use tsdownsample for time series downsampling

    main

    To use tsdownsample, instantiate one of the available downsampler classes and call the .downsample() method. The method returns an array of indices (ndarray[uint64]) which you can then use to slice your original data.

    from tsdownsample import MinMaxLTTBDownsampler
    import numpy as np
    
    # Create a time series
    y = np.random.randn(10_000_000)
    x = np.arange(len(y))
    
    # Downsample to 1000 points (assuming constant sampling rate)
    s_ds = MinMaxLTTBDownsampler().downsample(y, n_out=1000)
    
    # Select downsampled data
    downsampled_y = y[s_ds]
    
    # Downsample to 1000 points using the (possible irregularly spaced) x-data
    s_ds = MinMaxLTTBDownsampler().downsample(x, y, n_out=1000)
    
    # Select downsampled data
    downsampled_x = x[s_ds]
    downsampled_y = y[s_ds]
  5. Downsampling API reference

    main

    Each downsampling algorithm is implemented as a class with a downsample method.

    Method Signature: downsample([x], y, n_out, **kwargs) -> ndarray[uint64]

    Arguments:

    • x (optional): The x-axis data (must be non-strictly monotonic increasing and contain no NaNs).
    • y (mandatory): The y-axis data.
    • n_out (mandatory keyword): The desired number of output values. Note that if there are gaps in the time series, fewer than n_out indices may be returned.
    • **kwargs (optional): Algorithm-specific arguments (see algorithm table).

    Returns: A ndarray[uint64] of indices used to index the original data.

  6. Configure the maximum number of threads via TSDOWNSAMPLE_MAX_THREADS

    main

    The downsample_rs crate uses a global thread pool (POOL) powered by rayon for parallel execution. You can control the number of threads used by the pool by setting the TSDOWNSAMPLE_MAX_THREADS environment variable.

    If this variable is not set, the library defaults to the number of available parallel threads on the system. If parallelism cannot be determined, it defaults to 1 thread.

    export TSDOWNSAMPLE_MAX_THREADS=4
  7. Handle NaNs in time series data

    main

    The library provides specific classes to handle NaN values in the y data. You can either omit NaNs or return the index of the first NaN encountered in a bin.

    Policy: Omit NaNsPolicy: Return NaNs
    MinMaxDownsamplerNaNMinMaxDownsampler
    M4DownsamplerNaNM4Downsampler
    MinMaxLTTBDownsamplerNaNMinMaxLTTBDownsampler
    LTTBDownsampler(Not explicitly listed for LTTB)

    Note: NaNs are not supported for x-data.

  8. Available downsampling algorithms

    main

    The following classes are available for downsampling:

    DownsamplerDescription**kwargs
    MinMaxDownsamplerselects the min and max value in each binparallel
    M4Downsamplerselects the min, max, first and last value in each binparallel
    LTTBDownsamplerperforms the Largest Triangle Three Buckets algorithmparallel
    MinMaxLTTBDownsamplera two-step algorithm: first selects n_out * minmax_ratio min/max values, then reduces to n_out using LTTBparallel, minmax_ratio
  9. Implement a custom downsampler with AbstractDownsampler

    main

    To create a custom downsampling algorithm in Python, subclass AbstractDownsampler. You must implement the _downsample abstract method. The base class handles input validation, ensuring arrays are 1D, checking for contiguity (required for Rust-based implementations), and validating data types against provided regex lists.

    Key Methods to Implement:

    • _downsample(self, x, y, n_out, **kwargs): The core logic. It must return a np.ndarray of selected indices.

    Public API:

    • downsample(self, [x], y, n_out, **kwargs): The main entry point.
      • x (optional): 1D array of horizontal coordinates.
      • y: 1D array of vertical coordinates.
      • n_out: The number of points to keep.
      • Returns: np.ndarray of selected indices.
    from tsdownsample.downsampling_interface import AbstractDownsampler
    import numpy as np
    
    class MyDownsampler(AbstractDownsampler):
        def _downsample(self, x, y, n_out, **kwargs):
            # Return indices of the points to keep
            return np.linspace(0, len(y) - 1, n_out, dtype=int)
    
    # Usage
    downsampler = MyDownsampler()
    y = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
    indices = downsampler.downsample(y, n_out=3)
    # indices will be array([0, 2, 4])
  10. Implement a Rust-backed NaN-aware downsampler with AbstractRustNaNDownsampler

    main

    For downsamplers that need special handling for NaN values (typically only applicable to floating-point y data), subclass AbstractRustNaNDownsampler.

    This class uses the prefix downsample_nan to look up specialized functions in the Rust module. If the y data is not a floating-point type, it automatically strips the _nan suffix to fall back to standard downsampling functions, as non-float types cannot contain NaN values.