【问题标题】:How to find all local maxima and minima in a Python Pandas series without knowing the frequency of the window如何在不知道窗口频率的情况下找到 Python Pandas 系列中的所有局部最大值和最小值
【发布时间】:2021-05-23 00:21:57
【问题描述】:

作为我问题的背景,请允许我解释一下我要解决的问题。我有一个传感器正在收集压力数据。我正在将这些数据收集到一个 pandas 数据框中,结构如下:

DateTime                             Transmission Line PSI                
2021-02-18 11:55:34                  3.760
2021-02-18 11:55:49                  3.359
2021-02-18 11:56:04                  3.142
2021-02-18 11:56:19                  3.009
2021-02-18 11:56:34                  2.938
...                                    ...
2021-02-19 12:05:06                  3.013
2021-02-19 12:05:21                  3.011
2021-02-19 12:05:36                  3.009
2021-02-19 12:05:51                  3.009
2021-02-19 12:06:06                  3.007

我可以使用 pyplot 绘制数据框,并直观地查看为系统供电的压缩机何时运行、多久运行一次以及对系统加压需要多长时间。压力数据图:

从图像中可以明显看出,图左侧的周期比右侧的周期短得多。

我要解决的问题是我想以编程方式计算最后一个完整开关周期的最大压力、最小压力、周期长度和占空比。额外的好处是以编程方式计算 24 小时的总运行时间。

我想我需要对压力级数求导,我正在使用在python pandas: how to calculate derivative/gradient 找到的解决方案。

衍生系列剧情:

然后,当压缩机运行时(正数)而不是(零或负数),导数系列将以数字形式显示。我在想,然后我可以找到各个峰的所有最大值和最小值,并从那里得到它们之间的时间增量。

但是,我遇到的问题是到目前为止我发现的任何解决方案都需要我提前知道要使用多大的窗口(例如,使用 SciPy argrelextrema https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.argrelextrema.html 时的 order 参数)。

但我的数据系列的周期短至几分钟,理想情况下(如果我们没有泄漏!)周期应该延长到数小时或更长时间。使用短窗口会导致我在较长的周期中得到错误的最大值和最小值,而较长的窗口会导致我在较短的周期中错过许多最大值和最小值。

对于以编程方式查看上图中显而易见的内容有什么想法吗?

【问题讨论】:

  • 我在你的任何一个图中都没有看到任何明显的东西:数据太密集了,我几乎不知道你的工作周期有什么明确的特征。您需要指定它才能编写实现该定义的代码。或者,您可以尝试表示您的最大值和最小值,然后研究深度学习模型以了解区别。
  • @Prune 数据很密集,但如果放大到足够大,最大值和最小值会很明显。无论如何,它们在情节的右侧都很明显。我从来没有深入研究过深度学习,那么什么包是开始寻找的好方向?
  • 放大照片不会显示更多细节。我们仍然需要您对占空比定义的规范。至于深度学习……在发布指南中,要求参考或建议被特别列为题外话。如果您还不熟悉这个概念,那么您将面临一段不平凡的学习曲线。
  • 似乎导数系列中的最大值都高于某个阈值(0.01),最小值也是如此(-0.01)。你不能只过滤这些阈值的系列并用scipy.signal.find_peaks确定最大值/最小值
  • @Mr.T - 太好了.. 我认为这让我走上了正确的道路!虽然我没有事先过滤,但scipy.signal.find_peaks 中的高度参数让我可以做到这一点。我用否定的 DataFrame 重复该命令以找到负峰值。非常感谢!

标签: python pandas numpy scipy


【解决方案1】:

Mr.T 上面的评论有我的答案...使用scipy.signal.find_peaks 让我可以做我需要的事情。下面贴出代码。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter
import scipy.signal as sig

namespace = ['DateTime', 'Transmission Line PSI']
    
plt.rcParams["figure.figsize"] = [16.0, 9.0]
fig, ax = plt.subplots()
df = pd.read_csv(r'\\192.168.1.1\raid\graphdata.csv', names=namespace)

# convert imported date/time information to real datetimes and set as index
df['DateTime'] = pd.to_datetime(df['DateTime'])
df = df.set_index(df['DateTime']).drop('DateTime', axis=1)

# take first derivative of pressure data to show when pressure is rising or falling
df['deltas'] = df['Transmission Line PSI'].diff() / df.index.to_series().diff().dt.total_seconds()
df['deltas'] = df['deltas'].fillna(0)

peaks, _ = sig.find_peaks(df['deltas'], height=0.01)
neg_peaks, _ = sig.find_peaks(-df['deltas'], height=0.01)

# plotting peaks and neg_peaks against first derivative
plt.scatter(df.iloc[peaks].index, df.iloc[peaks]['deltas'])
plt.scatter(df.iloc[neg_peaks].index, df.iloc[neg_peaks]['deltas'])
plt.plot(df['deltas'])
plt.show()

# find timedeltas between all positive peaks - these are the periods of the cycle times
cycle_times = df.iloc[peaks].index.to_series().diff().dt.seconds.div(60, fill_value=0)

# plot periods
plt.plot(cycle_times)
plt.show()

峰对一阶导数的结果图:

cycle_times 示例:

>>> cycle_times
DateTime
2021-02-18 11:59:04     0.000000
2021-02-18 12:04:04     5.000000
2021-02-18 12:09:35     5.516667
2021-02-18 12:16:05     6.500000
2021-02-18 12:21:35     5.500000
                         ...    
2021-02-19 08:54:09    17.016667
2021-02-19 09:27:56    33.783333
2021-02-19 10:15:44    47.800000
2021-02-19 11:24:19    68.583333
2021-02-19 12:02:36    38.283333
Name: DateTime, Length: 267, dtype: float64

循环时间图:

https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.find_peaks.html

【讨论】:

    猜你喜欢
    • 2023-01-05
    • 2020-01-08
    • 2020-06-21
    • 1970-01-01
    • 2014-12-15
    • 1970-01-01
    • 2016-03-16
    • 2021-09-26
    • 1970-01-01
    相关资源
    最近更新 更多