我需要与scipy.optimize.curve_fit配合一些数据,这些数据看起来像图中的点。我使用了一个函数y(x) (参见下面的def ),它为x<x0提供了一个常数y(x)=c,否则就是一个多项式(例如第二条倾斜线y1 = mx+q)。
我给出了参数(x0, c, m, q)的合理的初步猜测,如图所示。拟合结果表明,除了第一个x0参数外,所有参数都得到了优化。
为什么会这样呢?我是如何定义函数testfit(x, *p)的吗?x0 (=p[0])出现在另一个函数中吗?

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# generate some data:
x = np.linspace(0,100,1000)
y1 = np.repeat(0, 500)
y2 = x[500:] - 50
y = np.concatenate((y1,y2))
y = y + np.random.randn(len(y))
def testfit(x, *p):
''' piecewise function used to fit
it's a constant (=p[1]) for x < p[0]
or a polynomial for x > p[0]
'''
x = x.astype(float)
y = np.piecewise(x, [x < p[0], x >= p[0]], [p[1], lambda x: np.poly1d(p[2:])(x)])
return y
# initial guess, one horizontal and one tilted line:
p0_guess = (30, 5, 0.3, -10)
popt, pcov = curve_fit(testfit, x, y, p0=p0_guess)
print('params guessed : '+str(p0_guess))
print('params from fit : '+str(popt))
plt.plot(x,y, '.')
plt.plot(x, testfit(x, *p0_guess), label='initial guess')
plt.plot(x, testfit(x, *popt), label='final fit')
plt.legend()输出
params guessed : (30, 5, 0.3, -10)
params from fit : [ 30. 0.04970411 0.80106256 -34.17194401]
OptimizeWarning: Covariance of the parameters could not be estimated category=OptimizeWarning)发布于 2018-06-16 21:58:53
正如kazemakase所建议的那样,我解决了这个问题,在我用来拟合的两个函数之间进行了平稳的转换(一条水平线,后面是一个多项式)。诀窍是将一个函数乘以sigmoid(x),另一个函数乘以1-sigmoid(x) (在下面定义了sigmoid(x) )。

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
x = np.linspace(0,100,1000)
y1 = np.repeat(0, 500)
y2 = x[500:] - 50
y = np.concatenate((y1,y2))
y = y + np.random.randn(len(y))
def testfit(x, *p):
''' function to fit the indentation curve
p = [x0,c, poly1d_coeffs ]'''
x = x.astype(float)
y = p[1]*(1-sigmoid(x-p[0],k=1)) + np.poly1d(p[2:])(x) * sigmoid(x-p[0],k=1)
return y
def sigmoid(x, k=1):
return 1/(1+np.exp(-k*x))
p0_guess = (30, 5, 0.3, -10 )
popt, pcov = curve_fit(testfit, x, y, p0=p0_guess)
print('params guessed : '+str(p0_guess))
print('params from fit : '+str(popt))
plt.figure(1)
plt.clf()
plt.plot(x,y, 'y.')
plt.plot(x, testfit(x, *p0_guess), label='initial guess')
plt.plot(x, testfit(x, *popt), 'k', label='final fit')
plt.legend()发布于 2018-06-13 15:31:15
我也有过类似的问题。最后,我使用np.gradient和一个卷积来平滑曲线,然后绘制它。类似于:
def mov_avg(n, data):
return np.convolve(data, np.ones((n,))/n, mode='valid')如果您想要一种更直接的方法,可以尝试以下方法:
def find_change(data):
def test_flag(pos):
grad = np.gradient(data) - np.gradient(data).mean()
return (grad[:pos]<0).sum() + (grad[pos:]>0).sum()
return np.vectorize(test_flag)(np.arange(len(data)-1)).argmax()
def find_gradient(pos, data):
return np.gradient(data[:pos]).mean(), np.gradient(data[pos:]).mean()
pos=find_change(x2)
print(pos, find_gradient(pos, data))第一个函数通过比较点梯度和平均梯度来计算梯度变化的点,找出梯度“大部分为正”的点。
希望它能帮上忙
https://stackoverflow.com/questions/50838346
复制相似问题