0

我正在尝试对我的数据进行分段拟合,但我需要使用任意数量的线段来进行。有时有三个部分;有时有两个。我将拟合系数存储在 actable 中,并将段的边界存储在 btable 中。

以下是我的界限的示例值:

btable = [[0.00499999989, 0.0244274978], [0.0244275965, 0.0599999987]]

以下是我的系数的示例值:

actable = [[0.0108687987, -0.673182865, 14.6420775], [0.00410866373, -0.0588355861, 1.07750032]]

这是我的代码的样子:

rfig = plt.figure()
<>various other plot specifications<>
x = np.arange(0.005, 0.06, 0.0001)
y = np.piecewise(x, [(x >= btable[i][0]) & (x <= btable[i][1]) for i in range(len(btable))], [lambda x=x: np.log10(actable[j][0] + actable[j][2] * x + actable[j][2] * x**2) for j in list(range(len(actable)))])
plt.plot(x, y)

问题是 lambda 将自己设置为列表的最后一个实例,因此它使用所有段的最后一个段的系数。我不知道如何在不使用 lambda 的情况下执行分段函数。

目前,我这样做是在作弊:

if len(btable) == 2:
    y = np.piecewise(x, [(x >= btable[i][0]) & (x <= btable[i][1]) for i in range(len(btable))], [lambda x: np.log10(actable[0][0] + actable[0][1] * x + actable[0][2] * x**2), lambda x: np.log10(actable[1][0] + actable[1][1] * x + actable[1][2] * x**2)])
else if len(btable) == 3:
    y = np.piecewise(x, [(x >= btable[i][0]) & (x <= btable[i][1]) for i in range(len(btable))], [lambda x: np.log10(actable[0][0] + actable[0][1] * x + actable[0][2] * x**2), lambda x: np.log10(actable[1][0] + actable[1][1] * x + actable[1][2] * x**2), lambda x: np.log10(actable[2][0] + actable[2][1] * x + actable[2][2] * x**2)])
else
    print('Oh no!  You have fewer than 2 or more than 3 segments!')

但这让我内心感到恶心。我知道必须有更好的解决方案。有人可以帮忙吗?

4

1 回答 1

0

这个问题很常见,Python的官方文档有一篇文章Why do lambdas defined in a loop with different values all return the same result?建议的解决方案:创建一个由循环变量初始化的局部变量,以捕获函数内后者的变化值。

也就是说,在它的定义中y足以替换

[lambda x=x: np.log10(actable[j][0] + actable[j][1] * x + actable[j][2] * x**2) for j in range(len(actable))]

经过

[lambda x=x, k=j: np.log10(actable[k][0] + actable[k][1] * x + actable[k][2] * x**2) for j in range(len(actable))]

顺便说一句,可以使用单边不等式来指定 numpy.piecewise 的范围:计算结果为 True 的最后一个条件将触发相应的函数。(这是一个有点违反直觉的优先级;使用第一个真实条件会更自然,就像 SymPy 所做的那样)。如果断点按升序排列,则应使用“x>=”不等式:

breaks = np.arange(0, 10)       # breakpoints
coeff = np.arange(0, 20, 2)     # coefficients to use
x = np.arange(0, 10, 0.1)
y = np.piecewise(x, [x >= b for b in breaks], [lambda x=x, a=c: a*x for c in coeff])

这里每个系数将用于从相应断点开始的区间;例如,在 range 中使用系数 c=0,在 range 中使用0<=x<1系数 c=2 1<=x<2,依此类推。

于 2016-12-19T02:29:15.950 回答