寻找两个峰之间的局部最小值

Finding local minimum between two peaks

我在 Pandas 中有一些时间序列数据,我需要从列中提取特定的局部最小值,以便将它们用作 LSTM 模型中的特征。为了可视化我正在寻找的内容,我附上了一个 Picture,其中带圆圈的点是我希望找到的值。

您在图表底部看到的其他红点是我尝试通过以下代码使用“argrelextrema”的失败尝试:

#Trying to Locate Minimum Values
df['HKL Min'] = df.iloc[argrelextrema(df.hkla.values, np.less_equal,order=50)[0]]['hkla']

#Plotting a range of values from dataset:
sns.lineplot(x=df.index[0:3000], y= 'hkla', data=df[0:3000], label='Hookload');
sns.scatterplot(x=df.index[0:3000], y= 'HKL Min', data=df[0:3000], s= 50, color ='red', label='HKL Min');

您可能会注意到,我的列数据具有重复模式,我希望定位的点是在两个“峰对”之间找到的最小值。Python 中是否有一些现有函数可以帮我定位这些具体点?任何形式的帮助将不胜感激。我也愿意接受其他可以解决我的问题的建议...

你可以用你的数据做这样的事情:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from scipy.signal import argrelextrema


np.random.seed(1234)
rs = np.random.randn(500)
xs = [0]
for r in rs:
    xs.append(xs[-1] * 0.999 + r)
df = pd.DataFrame(xs, columns=['point'])

给出了这个数据

point
0    0.000000
1    0.471435
2   -0.720012
3    0.713415
4    0.400050
..        ...
496  3.176240
497  3.007734
498  3.123841
499  1.045736
500  0.041935

[501 rows x 1 columns]

您可以通过使用参数来选择要标记本地 ma 或 min 的频率:

n = 10

df['min'] = df.iloc[argrelextrema(df.point.values, np.less_equal,
                    order=n)[0]]['point']
df['max'] = df.iloc[argrelextrema(df.point.values, np.greater_equal,
                    order=n)[0]]['point']


plt.scatter(df.index, df['min'], c='r')
plt.scatter(df.index, df['max'], c='r')
plt.plot(df.index, df['point'])
plt.show()

给出:

n 的另一个选择可能是(这完全取决于您想要什么):

n = 40

df['min'] = df.iloc[argrelextrema(df.point.values, np.less_equal,
                    order=n)[0]]['point']
df['max'] = df.iloc[argrelextrema(df.point.values, np.greater_equal,
                    order=n)[0]]['point']


plt.scatter(df.index, df['min'], c='r')
plt.scatter(df.index, df['max'], c='g')
plt.plot(df.index, df['point'])
plt.show()

要标记哪些点实际上在最大值和最小值的位置,您可以创建一个新的 df:

new_df = pd.DataFrame(np.where(df.T == df.T.max(), 1, 0),index=df.columns).T

它给出了关于 df 中哪一行是最大值或最小值的信息。否则,原始 df 在创建的 minmax 列中包含该信息,这些实例不是 nan

编辑:查找高于阈值的峰值

如果您对某个值以上的峰值感兴趣,那么您应该按以下方式使用 find_peaks

from scipy.signal import find_peaks 
peaks, _ = find_peaks(df['point'], height = 15)
plt.plot(df['point'])
plt.plot(peaks, df['point'][peaks], "x")
plt.show()

这将产生:

peaks,_


(array([304, 309, 314, 317, 324, 329, 333, 337, 343, 349, 352, 363, 366,
        369, 372, 374, 377, 379, 381, 383, 385, 387, 391, 394, 397, 400,
        403, 410, 413, 418, 424, 427, 430, 433, 436, 439, 442, 444, 448],
       dtype=int64),
 {'peak_heights': array([15.68868141, 15.97184882, 15.04790966, 15.6146908 , 16.49191501,
         18.0852033 , 18.11467247, 19.48469432, 21.32391722, 19.90407526,
         19.93683051, 24.40980129, 28.00319793, 26.1080406 , 24.44322213,
         23.16993982, 22.27505873, 21.47500832, 22.3236231 , 24.02484906,
         23.83727054, 24.32609486, 21.25365717, 21.10295203, 20.03162979,
         20.64021444, 19.78510855, 21.62624829, 22.34904425, 21.60431638,
         18.41968769, 18.24153961, 18.00747871, 18.02793964, 16.72552016,
         17.58573207, 16.90982675, 16.9905686 , 16.30563852])})

和图形化

我能够使用@Serge de Gosson de Varennes 提供的方法解决我的问题。我用 scipy “find_peaks()” 关闭了“argrelextrema”,如下所示:

df['Min'] = df.iloc[find_peaks(-df.column[0:3000], height=(-350000,-250000), threshold = None,
                           distance=200, )[0]]['column']

这里的高度输入让我可以选择在 y 方向上的间隔,这使得检测我在所述间隔内寻找的局部最小值变得非常容易。当绘制这样的结果时:

plt.plot(df.index[0:3000], df.column[0:3000])
plt.plot(df.index, df['Min'],'ro', color = 'red', label = 'Min Values')

我得到了以下graph

感谢您的协助!