查找斜率变化点作为自由参数- Python
Finding the point of a slope change as a free parameter- Python
假设我有两个数据列表如下:
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
y = [1, 2, 3, 4, 5, 6, 8, 10, 12, 14]
也就是说,很明显,仅仅为该数据拟合一条线是行不通的,而是数据中某个点的斜率发生了变化。 (很明显,人们可以很容易地从这个数据集中查明变化在哪里,但在我正在处理的数据集中它并不那么清楚所以让我们忽略它。)我猜是关于导数的东西,但这里的重点我想把它当作一个自由参数,我说 "it's this point, +/- this uncertainty, and here is the linear slope before and after this point."
请注意,如果更容易的话,我可以用数组来做到这一点。谢谢!
我不太清楚你想要什么,但你可以这样看进化(导数):
>>> 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]
然后找到它变化的点(二阶导数):
>>> dpy=[dy[i+1]-dy[i] for i in range(len(dy)-1)]
>>> dpy
[0, 0, 0, 0, 1, 0, 0, 0]
如果你想要这个点的索引:
>>> dpy.index(1)
4
可以为您提供斜率变化前最后一点的值:
>>> change=dpy.index(1)
>>> y[change]
5
在您的 y = [1, 2, 3, 4, 5, 6, 8, 10, 12, 14]
中,更改发生在索引 [4]
处(列表索引从 0 开始),此时 y 的值为 5
.
这是您的数据图:
您需要找到两个斜率(== 取两个导数)。首先求出每两点之间的斜率(使用numpy
):
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。然后取这个数组的导数,它告诉你斜率什么时候改变:
print (np.diff(m))
[ 0. 0. 0. 0. 1. 0. 0. 0.]
查找非零值的索引:
idx = np.nonzero(np.diff(m))[0]
print (idx)
# 4
由于我们对 x 取了一个导数,并且索引在 Python 中从零开始,idx+2
告诉您斜率在第六个点之前和之后是不同的。
您可以将斜率计算为每对点之间的差值(一阶导数)。然后检查斜率变化的位置(二阶导数)。如果它发生变化,则将索引位置附加到 idx
,即坡度发生变化的点集合。
请注意,第一个点没有唯一的斜率。第二对点会给你斜率,但你需要第三对才能测量斜率的变化。
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]
当然这可以在 Pandas 或 Numpy 中更有效地完成,但我只是给你一个简单的 Python 2 解决方案。
一个简单的条件列表理解应该也很有效,尽管它更难理解。
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])]
Knee point 可能是一个潜在的解决方案。
from kneed import KneeLocator
import numpy as np
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
y = np.array([1, 2, 3, 4, 5, 6, 8, 10, 12, 14])
kn = KneeLocator(x, y, curve='convex', direction='increasing')
# You can use array y to automatically determine 'convex' and 'increasing' if y is well-behaved
idx = (np.abs(x - kn.knee)).argmin()
>>> print(x[idx], y[idx])
6 6
假设我有两个数据列表如下:
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
y = [1, 2, 3, 4, 5, 6, 8, 10, 12, 14]
也就是说,很明显,仅仅为该数据拟合一条线是行不通的,而是数据中某个点的斜率发生了变化。 (很明显,人们可以很容易地从这个数据集中查明变化在哪里,但在我正在处理的数据集中它并不那么清楚所以让我们忽略它。)我猜是关于导数的东西,但这里的重点我想把它当作一个自由参数,我说 "it's this point, +/- this uncertainty, and here is the linear slope before and after this point."
请注意,如果更容易的话,我可以用数组来做到这一点。谢谢!
我不太清楚你想要什么,但你可以这样看进化(导数):
>>> 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]
然后找到它变化的点(二阶导数):
>>> dpy=[dy[i+1]-dy[i] for i in range(len(dy)-1)]
>>> dpy
[0, 0, 0, 0, 1, 0, 0, 0]
如果你想要这个点的索引:
>>> dpy.index(1)
4
可以为您提供斜率变化前最后一点的值:
>>> change=dpy.index(1)
>>> y[change]
5
在您的 y = [1, 2, 3, 4, 5, 6, 8, 10, 12, 14]
中,更改发生在索引 [4]
处(列表索引从 0 开始),此时 y 的值为 5
.
这是您的数据图:
您需要找到两个斜率(== 取两个导数)。首先求出每两点之间的斜率(使用numpy
):
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。然后取这个数组的导数,它告诉你斜率什么时候改变:
print (np.diff(m))
[ 0. 0. 0. 0. 1. 0. 0. 0.]
查找非零值的索引:
idx = np.nonzero(np.diff(m))[0]
print (idx)
# 4
由于我们对 x 取了一个导数,并且索引在 Python 中从零开始,idx+2
告诉您斜率在第六个点之前和之后是不同的。
您可以将斜率计算为每对点之间的差值(一阶导数)。然后检查斜率变化的位置(二阶导数)。如果它发生变化,则将索引位置附加到 idx
,即坡度发生变化的点集合。
请注意,第一个点没有唯一的斜率。第二对点会给你斜率,但你需要第三对才能测量斜率的变化。
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]
当然这可以在 Pandas 或 Numpy 中更有效地完成,但我只是给你一个简单的 Python 2 解决方案。
一个简单的条件列表理解应该也很有效,尽管它更难理解。
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])]
Knee point 可能是一个潜在的解决方案。
from kneed import KneeLocator
import numpy as np
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
y = np.array([1, 2, 3, 4, 5, 6, 8, 10, 12, 14])
kn = KneeLocator(x, y, curve='convex', direction='increasing')
# You can use array y to automatically determine 'convex' and 'increasing' if y is well-behaved
idx = (np.abs(x - kn.knee)).argmin()
>>> print(x[idx], y[idx])
6 6