关于数据拟合:找到斜率变化点作为自由参数 – Python

Finding the point of a slope change as a free parameter- Python

假设我有两个数据列表,如下所示:

1
2
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
y = [1, 2, 3, 4, 5, 6, 8, 10, 12, 14]

也就是说,很明显,仅仅将一条直线拟合到这些数据上是行不通的,而是在数据中的某个点改变了坡度。(很明显,我们可以很容易地从这个数据集中找出变化的位置,但在我正在处理的数据集中并不是很清楚,所以我们忽略它。)我猜,关于导数的一些东西,但这里的重点是我想把它当作一个自由参数,我说"这是这个点,+/-这个不确定性,这里是前面的线性斜率。在这一点之后。"

注意,如果数组更简单的话,我可以用它来做这个。谢谢!


以下是您的数据图:

enter image description here

你需要找到两个斜率(=取两个导数)。首先,找出每两点之间的坡度(使用numpy):

1
2
3
4
5
6
import numpy as np
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10],dtype=np.float)
y = np.array([1, 2, 3, 4, 5, 6, 8, 10, 12, 14],dtype=np.float)
m = np.diff(y)/np.diff(x)
print (m)
# [ 1.  1.  1.  1.  1.  2.  2.  2.  2.]

显然,在第六个区间(第六点和第七点之间),坡度从1变为2。然后取这个数组的导数,它告诉你坡度何时改变:

1
2
print (np.diff(m))
[ 0.  0.  0.  0.  1.  0.  0.  0.]

要查找非零值的索引:

1
2
3
idx = np.nonzero(np.diff(m))[0]
print (idx)
# 4

因为我们对x取了一个导数,并且在python中指数从零开始,所以idx+2告诉您,在第六点之前和之后的斜率是不同的。


您可以将坡度计算为每对点之间的差(一阶导数)。然后检查坡度变化的位置(二阶导数)。如果它发生变化,将索引位置附加到idx中,即坡度变化点的集合。

请注意,第一个点没有唯一的坡度。第二对点会给你一个坡度,但是你需要第三对点才能测量坡度的变化。

1
2
3
4
5
6
7
8
9
10
idx = []
prior_slope = float(y[1] - y[0]) / (x[1] - x[0])
for n in range(2, len(x)):  # Start from 3rd pair of points.
    slope = float(y[n] - y[n - 1]) / (x[n] - x[n - 1])
    if slope != prior_slope:
        idx.append(n)
    prior_slope = slope

>>> idx
[6]

当然,在熊猫或麻木的环境中,这可以更有效地完成,但我只是给您一个简单的python 2解决方案。

一个简单的条件列表理解也应该是相当有效的,尽管它更难理解。

1
2
3
idx = [n for n in range(2, len(x))
       if float(y[n] - y[n - 1]) / (x[n] - x[n - 1])
       != float(y[n - 1] - y[n - 2]) / (x[n - 1] - x[n - 2])]


我不太清楚你想要什么,但是你可以用这种方式看到进化过程(导数):

1
2
3
4
>>> y = [1, 2, 3, 4, 5, 6, 8, 10, 12, 14]
>>> dy=[y[i+1]-y[i] for i in range(len(y)-1)]
>>> dy
[1, 1, 1, 1, 1, 2, 2, 2, 2]

然后找出它的变化点(二阶导数):

1
2
3
>>> dpy=[dy[i+1]-dy[i] for i in range(len(dy)-1)]
>>> dpy
[0, 0, 0, 0, 1, 0, 0, 0]

如果需要此点的索引:

1
2
>>> dpy.index(1)
4

这可以为您提供坡度变化前最后一个点的值:

1
2
3
>>> change=dpy.index(1)
>>> y[change]
5

在您的y = [1, 2, 3, 4, 5, 6, 8, 10, 12, 14]中,变化发生在索引[4]处(列表索引从0开始),此时y的值为5