我正在分析以 1Hz 采样的压力数据。时间序列表现出“斜坡”(压力线性增加,然后突然下降),我想自动检测开始和停止时间。请注意,这些压力事件不是周期性的:
我的第一次尝试是find_peaks
在我的数据的平滑版本上使用 SciPy 的函数。
我首先使用SciPy's cookbook中描述的函数来平滑这些时间序列:
smoothed_pressure = smooth(df['Pressure'], window_len=21)
然后我申请find_peaks
找到mean_amplitude
平滑数据上方的最大峰值(红色)和该幅度下方的最小峰值(黄色):
mean_amplitude = np.mean(smoothed_pressure)
max_indices = find_peaks(smoothed_pressure, distance=200, height=mean_amplitude)[0]
min_indices = find_peaks(smoothed_pressure, distance=200, height=[0,mean_amplitude])[0]
plt.figure(figsize=(20,3))
plt.title(filename)
plt.plot(df['Time'], df["Pressure"])
plt.scatter(df[df.index.isin(max_indices-11)]['Time'], df[df.index.isin(max_indices-11)]["Pressure"], color='red', zorder=5)
plt.scatter(df[df.index.isin(min_indices-11)]['Time'], df[df.index.isin(min_indices-11)]["Pressure"], color='yellow', zorder=5)
在调整之后,distance
我设法让这个策略适用于这个特定的例子,但是这个解决方案不够健壮,并且在应用于其他数据集时会失败。
我正在寻找其他策略来解决这个问题。
我正在考虑在尝试识别峰值之前区分数据。我也愿意尝试机器学习策略。欢迎任何其他想法!
-------------------------------------------------- -------------------------------------------------- --------
编辑:实施MAXTRON的解决方案
正如 Maxtron 在下面的回答中所建议的那样,计算二阶导数是确定每个斜坡的停止时间的绝佳方法。
在下面的示例中,我将二阶导数应用于原始数据的(高度)平滑版本:
ds=pd.DataFrame()
mylength=61
smoothed_time = smooth(df['Time'], window_len=mylength)
smoothed_pressure = smooth(df['Pressure'], window_len=mylength)
ds['Pressure']=smoothed_pressure
ds['Time']=smoothed_time
然后我计算这个平滑信号的一阶和二阶导数:
ds['Pressure_first_derivative']=ds['Pressure'].diff() / ds['Time'].diff()
ds['Pressure_second_derivative']=ds['Pressure_first_derivative'].diff() / ds['Time'].diff()
二阶导数如下所示:
识别超过用户定义阈值 0.15 的样本是识别每个斜坡结束的良好起点:
max_indices=ds[ds['Pressure_second_derivative']>0.15].index-np.int(mylength/2)
可能有一些方法可以使阈值自动化。此外,由于每个峰值的多个样本超过了这个阈值,我认为find_peaks
仍然需要将每组点归结为一个样本。