pwlf: Piecewise Linear Fitting
pwlf is a Python library (v2.5.2) for fitting continuous piecewise linear functions to 1D data. It allows users to specify the number of line segments and uses global optimization (like differential evolution or L-BFGS-B) to find optimal breakpoint locations. The library also supports fitting with known breakpoints, constrained fits, and provides statistical properties like standard errors and R-squared values. It is actively maintained with regular releases.
Common errors
-
ValueError: bounds should be a sequence containing real valued (min, max) pairs for each value in x.
cause The `bounds` parameter provided to `fit()` or `fitfast()` is incorrectly formatted or contains non-numeric values. It expects a list of (min, max) tuples for each breakpoint.fixEnsure `bounds` is a list or tuple of `(lower_bound, upper_bound)` pairs, where the length of the list matches the number of breakpoints (which is `n_segments` for `fit` or `fitfast`). Example: `bounds=[(0.0, 5.0), (5.0, 10.0)]` for 2 segments with 1 breakpoint. -
LinAlgError: This typically means your regression problem is ill-conditioned.
cause This error occurs when the underlying linear algebra problem for the least squares fit is singular or ill-conditioned. Common reasons include having too few data points relative to the number of segments, all data points lying on a single line for multiple segments, or breakpoint bounds being too restrictive.fixCheck your data for sufficient variability and density. Reduce the number of line segments if you have sparse data. Adjust breakpoint bounds to be more flexible, or ensure there are enough data points within each segment. -
AttributeError: You have probably not performed a fit yet.
cause Methods like `predict()`, `calc_slopes()`, `standard_errors()`, or `r_squared()` are called before a fitting method (`fit()`, `fitfast()`, `fit_with_breaks()`) has successfully completed and established the model parameters.fixEnsure that one of the `fit` methods is called and executed without errors before attempting to use any post-fitting analysis or prediction methods. -
RuntimeWarning: invalid value encountered in less_equal (or greater)
cause This warning can occur in older versions of `pwlf` or `numpy` when breakpoints are very close to each other or on the boundary, leading to issues in internal array comparisons during optimization routines for `calc_slopes`.fixUpdate `pwlf` to the latest version (>=2.1.0), as this particular warning was addressed by changes in the `calc_slopes` logic during optimization. If the issue persists, review your data and initial breakpoint guesses/bounds to avoid nearly identical or problematic breakpoint locations.
Warnings
- breaking The `fitfast` method's results are no longer reproducible with previous versions (prior to v2.5.0). This is due to the removal of `pyDOE` as a dependency in favor of `scipy`'s own Latin Hypercube Sampling implementation for multi-start optimization.
- breaking In v2.1.0, the internal calculation for least squares changed from `linalg.inv` to `linalg.pinv`. While the API remains the same, this is a 'potentially backwards breaking change' as results, particularly standard error calculations, may differ from those obtained with older versions.
- deprecated Version 2.0.4 was the last release to officially support Python versions older than 3.6. Users on Python 3.5 or earlier should not upgrade beyond `pwlf==2.0.4`.
- gotcha Fitting a model with more unknowns (e.g., more line segments/breakpoints) than data points can lead to 'perfect' but physically meaningless fits (e.g., zero error, but erratic predictions between data points).
- gotcha The `fit` and `fitfast` methods use global optimization which involves stochastic elements (e.g., differential evolution, Latin Hypercube Sampling). Without setting a random seed, results for breakpoint locations can vary slightly between runs.
Install
-
pip install pwlf
Imports
- PiecewiseLinFit
import pwlf.PiecewiseLinFit
from pwlf import PiecewiseLinFit
Quickstart
import numpy as np
from pwlf import PiecewiseLinFit
# 1. Generate sample data
x = np.linspace(0, 10, 100)
y = 2 * x + np.random.normal(0, 0.5, 100) # First segment
y[50:] = -1 * x[50:] + 20 + np.random.normal(0, 0.5, 50) # Second segment
# 2. Initialize pwlf with your data
my_pwlf = PiecewiseLinFit(x, y)
# 3. Fit the function with a specified number of line segments (e.g., 2)
# The 'fit' method uses global optimization to find the best breakpoint locations.
breaks = my_pwlf.fit(2)
print(f"Optimal breakpoints: {breaks}")
# 4. Predict new y values using the fitted model
x_new = np.linspace(0, 10, 200)
y_predicted = my_pwlf.predict(x_new)
# You can also get other statistics after fitting
r_squared = my_pwlf.r_squared()
print(f"R-squared: {r_squared}")
# Example of getting slopes (after fit)
slopes = my_pwlf.slopes
print(f"Slopes of segments: {slopes}")