使用scipy进行条件曲线拟合?

4
假设我想对关闭灯光时记录的数据拟合一条直线,但现在我不小心把灯光开着,从第101个数据点开始,我的数据存在恒定偏移。
我该如何进行拟合?我尝试了为x设置条件,但出现了错误:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
请记得取消注释剩余代码(以遇到错误)。
import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt

d1 = np.random.normal(0,0.1, 100)
d2 = np.random.normal(3,0.1, 100)

x = np.arange(0,200)
y = np.concatenate((d1,d2))

plt.plot(x, y)

# def line(x, a, b, offset):
#     if x < 101:
#         y = a * x + b
#     else:
#         y = (a * x + b) + offset
#     return y
# 
# popt, pcov = optimize.curve_fit(line, xdata = x, ydata = y)
# 
# plt.plot(x, line(x, *popt), color = "firebrick")
plt.show()

预期输出: 在这里输入图片描述

1
虽然 Pavel 的技巧或许在这里管用,但对于更复杂的优化模型一定要小心。这个技巧会否定那些求解器的假设(在我看来)。另一个选择是使用 outer minimize_scalar 循环和手动曲线拟合式(因为使用 curve_fit 的 API 调整参数不太好)。在内部计算中,需要固定 offset。 - sascha
此外,我尝试将两个非常不同的函数结合在一起,并使用条件语句来处理x,例如return f(x) * (x => z) + g(x) * (x < z),结果发现所有参数的误差都是正无穷或负无穷。所以你是完全正确的! :) - komodovaran_
2个回答

5

我认为标准技巧是将布尔条件转换为整数因子:

def line(x, a, b, offset):
    return (a * x + b) + offset * (x>100)

非常有用的技巧!如果作为新项添加到自己的布尔型中,可以轻松地同时与多个偏移常量一起使用,适用于不同的范围。 - komodovaran_

2
你得到这个错误的原因是optimize调用你的line函数时传递了一个array值,而不仅仅是单个值。为了解决这个问题,你的line函数必须能够处理一组值。幸运的是,numpy有一个函数可以帮助你。
def line(x, a, b, offset):
    return np.piecewise(x, 
                        [x < 101, x >= 101],
                        [lambda x: a * x + b, lambda x: a * x + b + offset])

需要说明的是,它仍然没有收敛,但这是一个不同的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接