You can use numpy.piecewise() to create the piecewise function and then use curve_fit(), Here is the code

from scipy import optimize
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline

x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11, 12, 13, 14, 15], dtype=float)
y = np.array([5, 7, 9, 11, 13, 15, 28.92, 42.81, 56.7, 70.59, 84.47, 98.36, 112.25, 126.14, 140.03])

def piecewise_linear(x, x0, y0, k1, k2):
    return np.piecewise(x, [x < x0], [lambda x:k1*x + y0-k1*x0, lambda x:k2*x + y0-k2*x0])

p , e = optimize.curve_fit(piecewise_linear, x, y)
xd = np.linspace(0, 15, 100)
plt.plot(x, y, "o")
plt.plot(xd, piecewise_linear(xd, *p))

the output:

For an N parts fitting, please reference segments_fit.ipynb

Answer from HYRY on Stack Overflow
Top answer
1 of 12
88

You can use numpy.piecewise() to create the piecewise function and then use curve_fit(), Here is the code

from scipy import optimize
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline

x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11, 12, 13, 14, 15], dtype=float)
y = np.array([5, 7, 9, 11, 13, 15, 28.92, 42.81, 56.7, 70.59, 84.47, 98.36, 112.25, 126.14, 140.03])

def piecewise_linear(x, x0, y0, k1, k2):
    return np.piecewise(x, [x < x0], [lambda x:k1*x + y0-k1*x0, lambda x:k2*x + y0-k2*x0])

p , e = optimize.curve_fit(piecewise_linear, x, y)
xd = np.linspace(0, 15, 100)
plt.plot(x, y, "o")
plt.plot(xd, piecewise_linear(xd, *p))

the output:

For an N parts fitting, please reference segments_fit.ipynb

2 of 12
39

You can use pwlf to perform continuous piecewise linear regression in Python. This library can be installed using pip.

There are two approaches in pwlf to perform your fit:

  1. You can fit for a specified number of line segments.
  2. You can specify the x locations where the continuous piecewise lines should terminate.

Let's go with approach 1 since it's easier, and will recognize the 'gradient change point' that you are interested in.

I notice two distinct regions when looking at the data. Thus it makes sense to find the best possible continuous piecewise line using two line segments. This is approach 1.

import numpy as np
import matplotlib.pyplot as plt
import pwlf

x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
y = np.array([5, 7, 9, 11, 13, 15, 28.92, 42.81, 56.7, 70.59,
              84.47, 98.36, 112.25, 126.14, 140.03])

my_pwlf = pwlf.PiecewiseLinFit(x, y)
breaks = my_pwlf.fit(2)
print(breaks)

[ 1. 5.99819559 15. ]

The first line segment runs from [1., 5.99819559], while the second line segment runs from [5.99819559, 15.]. Thus the gradient change point you asked for would be 5.99819559.

We can plot these results using the predict function.

x_hat = np.linspace(x.min(), x.max(), 100)
y_hat = my_pwlf.predict(x_hat)

plt.figure()
plt.plot(x, y, 'o')
plt.plot(x_hat, y_hat, '-')
plt.show()

๐ŸŒ
NumPy
numpy.org โ€บ doc โ€บ stable โ€บ reference โ€บ generated โ€บ numpy.piecewise.html
numpy.piecewise โ€” NumPy v2.4 Manual
Define the signum function, which is -1 for x < 0 and +1 for x >= 0. >>> x = np.linspace(-2.5, 2.5, 6) >>> np.piecewise(x, [x < 0, x >= 0], [-1, 1]) array([-1., -1., -1., 1., 1., 1.])
Discussions

Python library for segmented regression (a.k.a. piecewise regression) - Data Science Stack Exchange
I am looking for a Python library that can perform segmented regression (a.k.a. piecewise regression). Example: More on datascience.stackexchange.com
๐ŸŒ datascience.stackexchange.com
October 16, 2015
How to do piecewise functions in python?
def pwise (x): if x < 0: result='less than' elif x==0: result = 'equal' ... #more elif followed by else return result More on reddit.com
๐ŸŒ r/learnpython
9
1
December 11, 2015
python - piecewise linear function with numpy.piecewise - Stack Overflow
I am trying to use the data from two x0 and y0 coordinate arrays to create a function that uses the provided x0 and y0 to compute a piecewise series of segments. For doing that, I create a function More on stackoverflow.com
๐ŸŒ stackoverflow.com
python - Fit points with a continuous, piecewise linear function with minimum number of points for each segment - Cross Validated
I have a set of two-dimensional data points that I want to fit with a continuous piecewise linear function with one break point. However, I want each of the two segments to be supported by a minimum number of data points. How can I do this in Python? More on stats.stackexchange.com
๐ŸŒ stats.stackexchange.com
๐ŸŒ
Songhuiming
songhuiming.github.io โ€บ pages โ€บ 2015 โ€บ 09 โ€บ 22 โ€บ piecewise-linear-function-and-the-explanation
piecewise linear function and the explanation โ€” pydata: Huiming's learning notes
from scipy import optimize def piecewise_linear(x, x0, x1, b, k1, k2, k3): condlist = [x < x0, (x >= x0) & (x < x1), x >= x1] funclist = [lambda x: k1*x + b, lambda x: k1*x + b + k2*(x-x0), lambda x: k1*x + b + k2*(x-x0) + k3*(x - x1)] return np.piecewise(x, condlist, funclist) p , e = optimize.curve_fit(piecewise_linear, x, y) xd = np.linspace(-30, 30, 1000) plt.plot(x, y, "o") plt.plot(xd, piecewise_linear(xd, *p)) ... python, AI, LLM, AGI, AIG, GPT, data mining, sklearn, pytorch, career growth, linux, deep learning, leetcode, dynamic programming, flask, highcharts, sql, webCrawl, random walk, multiprocessing, data visualization, numpy, tensorflow, quant, statsmodels, pandas, docker, matplotlib, data minging, remote access, mysql, base, tweepy, bokeh, sentiment analysis, map, apply, apply_async, git, PyQt, cx_freeze, tkinter, pelican, spyre, shiny, R, re
๐ŸŒ
Jekel
jekel.me โ€บ 2017 โ€บ Fit-a-piecewise-linear-function-to-data
Charles Jekel - jekel.me - Fitting a piecewise linear function to data
April 1, 2017 - A Python library to fit continuous piecewise linear functions to data was created. This library allows for the user to specify the desired number of line segments when fitting piecewise linear functions.
๐ŸŒ
GitHub
github.com โ€บ cjekel โ€บ piecewise_linear_fit_py
GitHub - cjekel/piecewise_linear_fit_py: fit piecewise linear data for a specified number of line segments ยท GitHub
A library for fitting continuous piecewise linear functions to data.
Starred by 348 users
Forked by 65 users
Languages ย  Python
๐ŸŒ
PyPI
pypi.org โ€บ project โ€บ pwlf
pwlf ยท PyPI
See this example which runs fit() function, then runs the fitfast() to compare the runtime differences! You can now install with pip. ... If you have conda, you can also install from conda-forge. ... This paper explains how this library works in detail. This is based on a formulation of a piecewise linear least squares fit, where the user must specify the location of break points.
      ยป pip install pwlf
    
Published ย  Jul 26, 2025
Version ย  2.5.2
Find elsewhere
๐ŸŒ
Mabouali
mabouali.com โ€บ 2024 โ€บ 02 โ€บ 04 โ€บ piecewise-linear-functions-part-i
Piecewise-Linear Functions: Part I โ€“ Moeโ€™s Homepage
February 4, 2024 - We are going to divide this document in two parts. The first part, this document, we are going to discuss piecewise linear functions (PLFs) and how to implement one in Python.
๐ŸŒ
ResearchGate
researchgate.net โ€บ publication โ€บ 331231072_pwlf_A_Python_Library_for_Fitting_1D_Continuous_Piecewise_Linear_Functions
(PDF) pwlf: A Python Library for Fitting 1D Continuous Piecewise Linear Functions
February 20, 2019 - A Python library to fit continuous piecewise linear functions to one dimensional data is presented. A continuous piecewise linear function has breakpoints which represent the termination points of the line segments. If breakpoint locations are known, then a least square fit is used to solve for the best continuous piecewise linear function.
Top answer
1 of 5
11

numpy.piecewise can do this.

piecewise(x, condlist, funclist, *args, **kw)

Evaluate a piecewise-defined function.

Given a set of conditions and corresponding functions, evaluate each function on the input data wherever its condition is true.

An example is given on SO here. For completeness, here is an example:

from scipy import optimize
import matplotlib.pyplot as plt
import numpy as np

x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11, 12, 13, 14, 15], dtype=float)
y = np.array([5, 7, 9, 11, 13, 15, 28.92, 42.81, 56.7, 70.59, 84.47, 98.36, 112.25, 126.14, 140.03])

def piecewise_linear(x, x0, y0, k1, k2):
    return np.piecewise(x, [x < x0, x >= x0], [lambda x:k1*x + y0-k1*x0, lambda x:k2*x + y0-k2*x0])

p , e = optimize.curve_fit(piecewise_linear, x, y)
xd = np.linspace(0, 15, 100)
plt.plot(x, y, "o")
plt.plot(xd, piecewise_linear(xd, *p))
2 of 5
10

The method proposed by Vito M. R. Muggeo[1] is relatively simple and efficient. It works for a specified number of segments, and for a continuous function. The positions of the breakpoints are iteratively estimated by performing, for each iteration, a segmented linear regression allowing jumps at the breakpoints. From the values of the jumps, the next breakpoint positions are deduced, until there are no more discontinuity (jumps).

"the process is iterated until possible convergence, which is not, in general, guaranteed"

In particular, the convergence or the result may depends on the first estimation of the breakpoints.

This is the method used in the R Segmented package.

Here is an implementation in python:

import numpy as np
from numpy.linalg import lstsq

ramp = lambda u: np.maximum( u, 0 )
step = lambda u: ( u > 0 ).astype(float)

def SegmentedLinearReg( X, Y, breakpoints ):
    nIterationMax = 10

    breakpoints = np.sort( np.array(breakpoints) )

    dt = np.min( np.diff(X) )
    ones = np.ones_like(X)

    for i in range( nIterationMax ):
        # Linear regression:  solve A*p = Y
        Rk = [ramp( X - xk ) for xk in breakpoints ]
        Sk = [step( X - xk ) for xk in breakpoints ]
        A = np.array([ ones, X ] + Rk + Sk )
        p =  lstsq(A.transpose(), Y, rcond=None)[0] 

        # Parameters identification:
        a, b = p[0:2]
        ck = p[ 2:2+len(breakpoints) ]
        dk = p[ 2+len(breakpoints): ]

        # Estimation of the next break-points:
        newBreakpoints = breakpoints - dk/ck 

        # Stop condition
        if np.max(np.abs(newBreakpoints - breakpoints)) < dt/5:
            break

        breakpoints = newBreakpoints
    else:
        print( 'maximum iteration reached' )

    # Compute the final segmented fit:
    Xsolution = np.insert( np.append( breakpoints, max(X) ), 0, min(X) )
    ones =  np.ones_like(Xsolution) 
    Rk = [ c*ramp( Xsolution - x0 ) for x0, c in zip(breakpoints, ck) ]

    Ysolution = a*ones + b*Xsolution + np.sum( Rk, axis=0 )

    return Xsolution, Ysolution

Example:

import matplotlib.pyplot as plt

X = np.linspace( 0, 10, 27 )
Y = 0.2*X  - 0.3* ramp(X-2) + 0.3*ramp(X-6) + 0.05*np.random.randn(len(X))
plt.plot( X, Y, 'ok' );

initialBreakpoints = [1, 7]
plt.plot( *SegmentedLinearReg( X, Y, initialBreakpoints ), '-r' );
plt.xlabel('X'); plt.ylabel('Y');

[1]: Muggeo, V. M. (2003). Estimating regression models with unknown breakpoints. Statistics in medicine, 22(19), 3055-3071.

๐ŸŒ
FICO
fico.com โ€บ fico-xpress-optimization โ€บ docs โ€บ dms2020-03 โ€บ solver โ€บ optimizer โ€บ python โ€บ HTML โ€บ chModeling_sec_secPWL.html
Piecewise linear functions
The above example creates variables x, y, z1, and z2, then constrains z1 and z2 to be (piecewise linear) functions of x, to be used with y in other constraints and in the objective function. The Xpress Python interface provides another, more intuitive way of specifying such a function with the method xpress.pwl, which is passed a dictionary associating intervals (defined as tuples of two elements) with linear functions.
๐ŸŒ
Stack Overflow
stackoverflow.com โ€บ a โ€บ 52953285
How to get piecewise linear function in Python - Stack Overflow
October 23, 2018 - I would like to get piecewise linear function from set of points. Here is visual example: import matplotlib.pyplot as plt x = [1,2,7,9,11] y = [2,5,9,1,11] plt.plot(x, y) plt.show() So I need a function that would take two lists and would return piecewise linear function back.
๐ŸŒ
Reddit
reddit.com โ€บ r/learnpython โ€บ how to do piecewise functions in python?
r/learnpython on Reddit: How to do piecewise functions in python?
December 11, 2015 -

Hi guys,

I'm using numpy and plotly to graph piecewise functions. I previously used matlab. I need help to essentially translate matlab piecewise functions into something I can use in python. Here's what I had in matlab:

Constant1 = 5;
Constant2 = 10;

Formula1 = @(x,y) x*Constant1;
Formula2 = @(x,y) x*Constant2;

MainFormula = @(x,y) [Formula1(x,y)*(y<=5) + Formula2(x,y)*(y>5)];

So what this would essentially do is make 'MainFormula' equal to 'Formula1' for all values of y less than or equal to 5, and it would make 'MainFormula' equal to 'Formula2' for all values of y greater than 5.

I would really appreciate any help with this.

Thanks

Top answer
1 of 2
2
def pwise (x): if x < 0: result='less than' elif x==0: result = 'equal' ... #more elif followed by else return result
2 of 2
1
The direct translation would be this: constant1 = 5 constant2 = 10 formula1 = lambda x: x*constant1 formula2 = lambda x: x*constant2 main_formula = lambda x, y: formula1(x)*(y <= 5) + formula2(x)*(y > 5) Note that I am using python style conventions. All of your variable names could be used as-is, but for style reasons lowercase variable names separated by _ are usually used. Same with the spaces I added in x,y, y<=5, and y>5, they aren't required, just recommended for readability reasons. These style recommendations are found in pep8 , and can be checked automatically by a program of the same name. Further, you could do, for example lambda x, y: x*constant1, it doesn't hurt anything, but it is unnecessary and I think it makes the code less clear. However, assuming you are using numpy arrays (which you should be), it would be easier to do this: def formula(x, y, const1=5, const2=10, sep=5): x1 = x.copy() x1[y <= sep] *= const1 x1[y > sep] *= const2 return x You can then use formula in the exact same way as MainFormula. It will default to using 5 for the first constant and 10 for the second, and 5 for the value of y to use to differentiate the two, but you can change that by passing different values to the function, such as formula(x, y, sep=200), or formula(x, y, 50, 100). If you don't care about losing your original x, you can simplify this further: def formula(x, y, const1=5, const2=10, sep=5): x[y <= sep] *= const1 x[y > sep] *= const2 In this case, whatever array you pass to formula as x will be changed in-place, so nothing is returned. This will be considerably faster than any of the previous approaches when dealing with large datasets. You could even simplify this further by doing the y calculation in the function call if you wanted: def formula(x, isy, const1=5, const2=10): x[isy] *= const1 x[~isy] *= const2 And then call it like this: formula(x, y<=5) The final approach you could do is to handle x separately: def formula(isy, const1=5, const2=10): return isy*const1 + ~isy*const2 or: lambda isy: isy*constant1 + ~isy*constant2 And then call it like this: x1 = x*isy(y <=5)
๐ŸŒ
NumPy
numpy.org โ€บ doc โ€บ 2.1 โ€บ reference โ€บ generated โ€บ numpy.piecewise.html
numpy.piecewise โ€” NumPy v2.1 Manual
Define the signum function, which is -1 for x < 0 and +1 for x >= 0. >>> x = np.linspace(-2.5, 2.5, 6) >>> np.piecewise(x, [x < 0, x >= 0], [-1, 1]) array([-1., -1., -1., 1., 1., 1.])
๐ŸŒ
NumPy
numpy.org โ€บ devdocs โ€บ reference โ€บ generated โ€บ numpy.piecewise.html
numpy.piecewise โ€” NumPy v2.5.dev0 Manual
Define the signum function, which is -1 for x < 0 and +1 for x >= 0. >>> x = np.linspace(-2.5, 2.5, 6) >>> np.piecewise(x, [x < 0, x >= 0], [-1, 1]) array([-1., -1., -1., 1., 1., 1.])
๐ŸŒ
Readthedocs
piecewise-regression.readthedocs.io
piecewise-regression โ€” piecewise-regression 1 documentation
The package is tested on Python 3.7, 3.8, 3.9 and 3.10. The package requires some x and y data to fit. You need to specify either a) some initial breakpoint guesses as start_values or b) how many breakpoints you want to fit as n_breakpoints (or both). Here is an elementary example, assuming we already have some data x and y: import piecewise_regression pw_fit = piecewise_regression.Fit(x, y, n_breakpoints=2) pw_fit.summary()
๐ŸŒ
GitHub
github.com โ€บ DataDog โ€บ piecewise
GitHub - DataDog/piecewise: ## Auto-archived due to inactivity. ## Functions for piecewise regression on time series data
Start by preparing your data as list-likes of timestamps (independent variables) and values (dependent variables). import numpy as np t = np.arange(10) v = np.array( [2*i for i in range(5)] + [10-i for i in range(5, 10)] ) + np.random.normal(0, 1, 10) Now, you're ready to import the piecewise() function and fit a piecewise linear regression.
Starred by 105 users
Forked by 36 users
Languages ย  Python 100.0% | Python 100.0%
๐ŸŒ
Scikit-hep
scikit-hep.org โ€บ pyhf โ€บ examples โ€บ notebooks โ€บ learn โ€บ InterpolationCodes.html
Piecewise Linear Interpolation โ€” pyhf 0.7.1.dev343 documentation
The interpolate_deltas() function defined above does this for us. ... alphas = np.linspace(-1.0, 1.0) deltas = [interpolate_deltas(down_1, nom_1, up_1, alpha) for alpha in alphas] deltas[:5] ... [array([-2.]), array([-1.91836735]), array([-1.83673469]), array([-1.75510204]), array([-1.67346939])] So now that weโ€™ve generated the deltas from the nominal measurement, we can plot this to see how the linear interpolation works in the single-bin case, where we plot the measured values in black, and the interpolation in dashed, blue.