【问题标题】:Count Number of cycles in graph/ plot using Python / Pandas / Numpy使用 Python / Pandas / Numpy 计算图形/绘图中的循环数
【发布时间】:2019-07-17 19:02:11
【问题描述】:

如何从使用 python/pandas/numpy 库在 matplotlib 中绘制的图表中找出 Y 值(速度)从 700 -800 RPM 上升和下降到 1600 到 1800 RPM 的次数,反之亦然。我使用 matplotlib 和 dataframe 绘制了这张图。

预期的输出应该是---> 速度上升的次数 = 2 和下降的次数 = 2 查看附图

下面附上图片/图表以获得更多说明

enter image description here

fig = plt.figure(figsize =(18,10))

ax =plt.subplot(311)
plt.plot(df.speed)

ax.set_yticks([0, 500, 700, 1000, 1500, 1700, 2000])

ax.set_xlabel("Time (Seconds)")
ax.set_ylabel("Speed (RPM)")
plt.grid()
plt.show()

【问题讨论】:

  • df.speed 看起来像什么?它只是一个整数列表吗?
  • 是的,它只是整数值。请参阅附加的图像文件以获得更多说明。
  • @Analyst 您可以使用df.speed 的时间导数,并且只检查符号更改了多少次。我不知道您的真实数据有多少抖动,但从图像上看,斜坡看起来很干净,因此该方法可以工作。
  • @Guimute:真实数据太大,如果我在这里绘制,理解起来很复杂。这就是我根据 1 天数据绘制图表的原因。

标签: python pandas numpy dataframe matplotlib


【解决方案1】:

这是一个矢量化的解决方案:

import pandas as pd

df = pd.DataFrame({'speed': [0,1600,0,1600,1600,1600,0,0,0]})

# Check if values are above or below a threshold
threshold = 1500
df['over_threshold'] = df['speed'] > threshold

# Compare to the previous row
# If over_threshold has changed, 
# then you either went above or fell below the threshold
df['changed'] = df['over_threshold'] != df['over_threshold'].shift(1)

# First one has, by definition, has no previous value, so we should omit it
df = df.loc[1:,]

# Count how many times a row is newly above or below threshold
counts = df.loc[df['changed']].groupby('over_threshold').agg({'changed': 'count'})
counts.index = ["Down", "Up"]
counts.columns = ["Count"]
counts

#     Count
#Down   2
#Up     2

然后,您将计算上升或下降的次数。

【讨论】:

  • 感谢您的代码。您的代码工作正常,但我没有得到预期的结果。它给了我数据框中每个点(1 秒数据)的总计数。如果您查看随附的图表,则预期输出应该是...上升次数 = 2 和下降次数 = 2。
  • 我更新了代码以包含一些虚拟数据并澄清输出显示 2 个上升和 2 个下降
  • 谢谢,考虑到您的 df,您的代码是正确的。我想计算从 700RPM 到 1600RPM 的加速次数和从 1600RPM 到 700RPM 的减速次数。如果速度从 700 增加到 800 或从 1600 减少到 1500,那么它不应该计算跳跃,即“UP / DOWN = 0”。如果速度从 700 增加到 1600,步长为 700、900、1400、1600,那么它应该计算“UP = 1”而不是 3,反之亦然(它不应该在速度增加或减少之间计算)。如果您查看附加的图像文件,您会得到更多的说明。
  • UP = 1 或 Down =1 当且仅当速度差大于或等于 900 RPM 即 (1600 -700) RPM
  • e. g df = pd.DataFrame({'engspd': [0,500,700,1200,1200,1700,1700,1600,1600,700,600,800,800,900,600,700,700,1300,1800,1900,1900,1600,1600,1300,1300,1100,1100,700,700,700 ,0]}) 对于高于 df 的预期输出应为:Up = 2 & Down =2
【解决方案2】:
# state variables
decreasing = False
increasing = False
last_above = False
last_below = False
drop_count = 0
jump_count = 0

for rpm_str in df:
    rpm = int(rpm_str)    # Because OP indicated the data was a string
    # Crossing threshold
    if ((last_below or decreasing) and rpm < 700):
        drop_count = drop_count + 1
        decreasing = False
        last_below = False
    elif ((last_above or increasing) and rpm > 1600):
        jump_count = jump_count + 1
        increasing = False
        last_above = False
    if (last_above and rpm < 1600):
        decreasing = True
        increasing = False
    elif (last_below and rpm > 700):
        increasing = True
        decreasing = False

    # State
    last_below = False
    last_above = False
    if (rpm < 700):
        last_below = True
    elif (rpm > 1600):
        last_above = True

这不是一个完美的解决方案,可能会遗漏一些边缘情况,但您的数据看起来很正常

【讨论】:

  • 您可以在if 中弹出括号并在此处使用一些elif ;)
  • @Guimute 对于这样的状态机,我尽量避免使用 elif,因为我经常在不应该使用它们的时候使用它们,哈哈,但它们在这里会有所帮助。另外,我喜欢括号,因为我来自其他语言,python 不是我的第一个。
  • @ZacharyOldham:我的数据集很大,但我试图仅通过 1 天的数据来计算它。如果它有效,那么我将使用类似的逻辑来完成数据。我正在尝试在 Jupyter Notebook 中运行上述脚本,但出现以下错误。! 'str' 和 'int' 的实例之间不支持 '
  • 可能类似于for rpm in df.speedfor rpm in df["speed"]?
  • @Analyst 您是从文件中读取值而不是转换它们吗?
【解决方案3】:

试试下面的代码:

y 是 y 数据 (rpm) lim 是循环开始时的 rpm 量

cycles = 0
for i in range(len(y)):
    if y[i] >= lim:
        cycles += 1
        while y[i] >= lim:
            i += 1

【讨论】:

  • lim 在您对其进行测试时还不存在。
猜你喜欢
  • 1970-01-01
  • 2022-12-10
  • 2021-11-25
  • 2014-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-06
  • 2016-09-29
相关资源
最近更新 更多