谢谢你们,我发现这很有用。如果有人想要这个问题的通用解决方案,我写了一个深受上面 sn-ps 启发的:
import numpy as np
from scipy.optimize import leastsq
def multiple_reg(x, y, f, const, params0, **kwargs):
"""Do same non-linear regression on multiple curves
"""
def leastsq_func(params, *args):
x, y = args[:2]
const = args[2:]
yfit = []
for i in range(len(x)):
yfit = np.append(yfit, f(x[i],*const[i],*params))
return y-yfit
# turn const into 2d-array if 1d is given
const = np.asarray(const)
if len(const.shape) < 2:
const = np.atleast_2d(const).T
# ensure that y is flat and x is nested
if hasattr(y[0], "__len__"):
y = [item for sublist in y for item in sublist]
if not hasattr(x[0], "__len__"):
x = np.tile(x, (len(const), 1))
x_ = [item for sublist in x for item in sublist]
assert len(x_) == len(y)
# collect all arguments in a tuple
y = np.asarray(y)
args=[x,y] + list(const)
args=tuple(args) #doesn't work if args is a list!!
return leastsq(leastsq_func, params0, args=args, **kwargs)
此函数接受各种长度的 xs 和 ys,因为它们存储在嵌套列表中,而不是 numpy ndarrays。对于这个线程中提出的特殊情况,该函数可以这样使用:
def fit(x,T,A,n,m):
return A/(n+1.0)*np.power(T,(n+1.0))*np.power(x,m)
# prepare dataset with some noise
params0 = [0.001, 1.01, -0.8]
Ts = [10, 50]
x = np.linspace(10, 100, 100)
y = np.empty((len(Ts), len(x)))
for i in range(len(Ts)):
y[i] = fit(x, Ts[i], *params) + np.random.uniform(0, 0.01, size=len(x))
# do regression
opt_params, _ = multiple_reg(x, y, fit, Ts, params0)
通过绘制数据和回归线来验证回归
import matplotlib.pyplot as plt
for i in range(len(Ts)):
plt.scatter(x, y[i], label=f"T={Ts[i]}")
plt.plot(x, fit(x, Ts[i], *opt_params), '--k')
plt.legend(loc='best')
plt.show()