The correct way to implement piecewise function in pandas / numpy

I need to create a function to go to curve_fit. In my case, a function is best defined as a piecewise function.

I know that the following does not work, but I show it because it makes the purpose of the function clear:

def model_a(X, x1, x2, m1, b1, m2, b2):
    '''f(x) has form m1*x + b below x1, m2*x + b2 above x2, and is
    a cubic spline between those two points.'''
    y1 = m1 * X + b1
    y2 = m2 * X + b2
    if X <= x1:
        return y1    # function is linear below x1
    if X >= x2:
        return y2    # function is linear above x2
    # use a cubic spline to interpolate between lower
    # and upper line segment
    a, b, c, d = fit_cubic(x1, y1, x2, y2, m1, m2)
    return cubic(X, a, b, c, d)

The problem, of course, is that X is a pandas series, and the form (X <= x1)is evaluated next to Boolean ones, so this fails with the message "The truth value of the series is ambiguous."

It seems to be np.piecewise()designed specifically for this situation: "Wherever the condlist [i] parameter is True, funclist [i] (x) is used as the output value." So I tried this:

def model_b(X, x1, x2, m1, b1, m2, b2):
    def lo(x):
        return m1 * x + b1
    def hi(x):
        return m2 * x + b2
    def mid(x):
        y1 = m1 * x + b1
        y2 = m2 * x + b2
        a, b, c, d = fit_cubic(x1, y1, x2, y2, m1, m2)
        return a * x * x * x + b * x * x + c * x + d

    return np.piecewise(X, [X<=x1, X>=x2], [lo, hi, mid])

But this fails with this call:

return np.piecewise(X, [X<=x1, X>=x2], [lo, hi, mid])

"IndexError: ". , , condlist funclist, , funclist .

?

+4
1

NumPy np.piecewise list/ndarray -centric:

# undocumented: single condition is promoted to a list of one condition
if isscalar(condlist) or (
        not isinstance(condlist[0], (list, ndarray)) and x.ndim != 0):
    condlist = [condlist]

, X - , condlist = [X<=x1, X>=x2] - Series. condlist[0] a list, a ndarray, condlist "" :

condlist = [condlist]

, , condlist NumPy, np.piecewise:

X = X.values

,

import numpy as np
import pandas as pd
def model_b(X, x1, x2, m1, b1, m2, b2):
    def lo(x):
        return m1 * x + b1
    def hi(x):
        return m2 * x + b2
    def mid(x):
        y1 = m1 * x + b1
        y2 = m2 * x + b2
        # a, b, c, d = fit_cubic(x1, y1, x2, y2, m1, m2)
        a, b, c, d = 1, 2, 3, 4
        return a * x * x * x + b * x * x + c * x + d
    X = X.values
    return np.piecewise(X, [X<=x1, X>=x2], [lo, hi, mid])

X = pd.Series(np.linspace(0, 100, 100))
x1, x2, m1, b1, m2, b2 = 30, 60, 10, 5, -20, 30
f = model_b(X, x1, x2, m1, b1, m2, b2)
+5

Source: https://habr.com/ru/post/1693136/


All Articles