Python:精确定位坡度的线性部分
我有几个图,如下所示: 我想知道有什么样的方法可以找到x轴大约5.5到8之间的斜率。在有几个这样的图的地方,我更想知道是否有一种方法可以自动找到斜率值 有什么建议吗 我在想Python:精确定位坡度的线性部分,python,matplotlib,graph,Python,Matplotlib,Graph,我有几个图,如下所示: 我想知道有什么样的方法可以找到x轴大约5.5到8之间的斜率。在有几个这样的图的地方,我更想知道是否有一种方法可以自动找到斜率值 有什么建议吗 我在想polyFit(),或者线性回归。问题是我不确定如何自动找到值。如果您的数据“模型”包含的数据大多符合直线,最后有一些异常值或摆动位,您可以尝试该算法 这里(非常冗长,抱歉)的伪代码是: choose a small threshold distance D for N iterations: pick two r
polyFit()
,或者线性回归。问题是我不确定如何自动找到值。如果您的数据“模型”包含的数据大多符合直线,最后有一些异常值或摆动位,您可以尝试该算法
这里(非常冗长,抱歉)的伪代码是:
choose a small threshold distance D
for N iterations:
pick two random points from your data, a and b
fit a straight line, L, to a and b
count the inliers: data points within a distance D of the line L
save the parameters of the line with the most inliers so far
estimate the final line using ALL the inliers of the best line
可以使用将数据简化为一组较小的线段。该算法允许您指定一个epsilon
,以便每个数据点与某个线段的距离不超过epsilon
。线段的斜率将给出曲线斜率的粗略估计
有一个这只是一个可能的解决方案,它将找到点的直线段,该直线段具有比预设最小值长的最小chi^2值
from matplotlib.pyplot import figure, show
from numpy import pi, sin, linspace, exp, polyfit
from matplotlib.mlab import stineman_interp
x = linspace(0,2*pi,20);
y = x + sin(x) + exp(-0.5*(x-2)**2);
num_points = len(x)
min_fit_length = 5
chi = 0
chi_min = 10000
i_best = 0
j_best = 0
for i in range(len(x) - min_fit_length):
for j in range(i+min_fit_length, len(x)):
coefs = polyfit(x[i:j],y[i:j],1)
y_linear = x * coefs[0] + coefs[1]
chi = 0
for k in range(i,j):
chi += ( y_linear[k] - y[k])**2
if chi < chi_min:
i_best = i
j_best = j
chi_min = chi
print chi_min
coefs = polyfit(x[i_best:j_best],y[i_best:j_best],1)
y_linear = x[i_best:j_best] * coefs[0] + coefs[1]
fig = figure()
ax = fig.add_subplot(111)
ax.plot(x,y,'ro')
ax.plot(x[i_best:j_best],y_linear,'b-')
show()
从matplotlib.pyplot导入图,显示
从numpy导入pi、sin、linspace、exp、polyfit
从matplotlib.mlab导入
x=linspace(0,2*pi,20);
y=x+sin(x)+exp(-0.5*(x-2)**2);
点数=len(x)
最小配合长度=5
chi=0
迟敏=10000
i_best=0
j_最佳=0
对于范围内的i(长度(x)-最小配合长度):
对于范围内的j(i+最小拟合长度,len(x)):
coefs=polyfit(x[i:j],y[i:j],1)
y_线性=x*coefs[0]+coefs[1]
chi=0
对于范围(i,j)内的k:
chi+=(y_线性[k]-y[k])**2
如果chi
我可以看到,对于更大的数据集,这个问题越来越严重……在数据集中查找线性部分的一般方法是计算函数的二阶导数,然后查看它(接近)零的位置。在解决问题的方法上有几件事要考虑:
- 如何计算噪声数据的二阶导数?一种快速而简单的方法,可以很容易地适应不同的噪声水平、数据集大小和线性面片的预期长度,就是用一个等于高斯函数二阶导数的卷积核来卷积数据。可调部分是内核的宽度
- 在你的上下文中,“接近零”是什么意思?要回答这个问题,你必须用你的数据进行实验
- 该方法的结果可作为上述chi^2方法的输入,以确定数据集中的候选区域
from matplotlib import pyplot as plt
import numpy as np
# create theoretical data
x_a = np.linspace(-8,0, 60)
y_a = np.sin(x_a)
x_b = np.linspace(0,4,30)[1:]
y_b = x_b[:]
x_c = np.linspace(4,6,15)[1:]
y_c = np.sin((x_c - 4)/4*np.pi)/np.pi*4. + 4
x_d = np.linspace(6,14,120)[1:]
y_d = np.zeros(len(x_d)) + 4 + (4/np.pi)
x = np.concatenate((x_a, x_b, x_c, x_d))
y = np.concatenate((y_a, y_b, y_c, y_d))
# make noisy data from theoretical data
y_n = y + np.random.normal(0, 0.27, len(x))
# create convolution kernel for calculating
# the smoothed second order derivative
smooth_width = 59
x1 = np.linspace(-3,3,smooth_width)
norm = np.sum(np.exp(-x1**2)) * (x1[1]-x1[0]) # ad hoc normalization
y1 = (4*x1**2 - 2) * np.exp(-x1**2) / smooth_width *8#norm*(x1[1]-x1[0])
# calculate second order deriv.
y_conv = np.convolve(y_n, y1, mode="same")
# plot data
plt.plot(x,y_conv, label = "second deriv")
plt.plot(x, y_n,"o", label = "noisy data")
plt.plot(x, y, label="theory")
plt.plot(x, x, "0.3", label = "linear data")
plt.hlines([0],-10, 20)
plt.axvspan(0,4, color="y", alpha=0.2)
plt.axvspan(6,14, color="y", alpha=0.2)
plt.axhspan(-1,1, color="b", alpha=0.2)
plt.vlines([0, 4, 6],-10, 10)
plt.xlim(-2.5,12)
plt.ylim(-2.5,6)
plt.legend(loc=0)
plt.show()
结果是:
smooth\u width
是卷积核的宽度。要调整噪声量,请将random.normal中的值0.27
更改为不同的值。请注意,这种方法在靠近数据空间边界的地方不能很好地工作
如您所见,二阶导数(蓝线)的“接近零”要求对于黄色部分非常适用,其中数据是线性的。是5.5和8固定的,还是您需要以某种方式自动找到它们?c.f.5.5和8只是基于图表的估计值。它们确实显示了我希望计算坡度的大致位置。我想我们需要更多的信息来帮助你。您希望得到什么样的数据?在不了解更多采样数据的特征的情况下,很难给出关于曲线拟合的一般建议。数据是否总是包含一些重要的线性部分?谢谢您的解释。你能给我介绍一些文章吗?在这些文章中,我能理解为什么将带噪数据与高斯函数的二阶导数进行卷积会返回带噪函数的平滑二阶导数?