我希望最有效的方法在包含数千个值的巨大数据点集中查找局部最大值。输入使用两个带有x和y值的长列表。
考虑这个简单的例子:
xval = [-0.15, -0.02, 0.1, 0.22, 0.36, 0.43, 0.58, 0.67, 0.79, 0.86, 0.96 ]
yval = [-0.09, 0.13, -0.01, -0.1, -0.05, 0.2, 0.56, 0.47, 0.35, 0.43, 0.69]
所需的输出是具有峰值索引的列表,这里locMaxId = [1,6,10]。 比较最近的邻居是解决方案,但是对于10k值?
答案 0 :(得分:4)
你可以让numpy处理迭代,即矢量化它:
def local_maxima(xval, yval):
xval = np.asarray(xval)
yval = np.asarray(yval)
sort_idx = np.argsort(xval)
yval = yval[sort_idx]
gradient = np.diff(yval)
maxima = np.diff((gradient > 0).view(np.int8))
return np.concatenate((([0],) if gradient[0] < 0 else ()) +
(np.where(maxima == -1)[0] + 1,) +
(([len(yval)-1],) if gradient[-1] > 0 else ()))
编辑因此代码首先计算从每个点到nex(gradient
)的变化。下一步有点棘手...如果你做np.diff((gradient > 0)
,结果布尔数组是True
,其中从增长(> 0
)到不增长({{1} })。通过使其成为与布尔数组大小相同的signed int,您可以区分从增长到不增长(<= 0
)到相反(-1
)的转换。通过采用与布尔数组具有相同dtype大小的有符号整数类型+1
,我们避免复制数据,如果我们执行较少hacky .view(np.int8)
会发生这种情况。剩下的就是处理第一个和最后一个点,并将所有点连接成一个数组。我今天发现的一件事是,如果你在发送给.astype(int)
的元组中包含一个空列表,它会以dtype np.concatenate
的空数组形式出现,最终成为dtype的类型。结果,因此上面的代码中空元组的连接更加复杂。
有效:
np.float
速度相当快:
In [2]: local_maxima(xval, yval)
Out[2]: array([ 1, 6, 10], dtype=int64)
此外,大部分时间是将数据从列表转换为数组并对其进行排序。如果您的数据已经排序并保存在数组中,那么您可以将性能提高5倍以上。