【问题标题】:Step/Spike detection breakdown for pandas dataframe graph?熊猫数据框图的步长/尖峰检测故障?
【发布时间】:2020-07-02 18:22:14
【问题描述】:

我目前正在尝试学习如何通过 pandas 和 matplotlib 使用 csv 数据。我有这个问题,对于一个明显有数据峰值的数据集,我需要在评估任何东西之前“清理”它。但我很难理解如何“检测”图表中的尖峰......

所以我正在处理的数据集如下:

df = pd.DataFrame({'price':[340.6, 35.66, 33.98, 38.67, 32.99, 32.04, 37.64, 
                            38.22, 37.13, 38.57, 32.4, 34.98, 36.74, 32.9,
                            32.52, 38.83, 33.9, 32.62, 38.93, 32.14, 33.09, 
                            34.25, 34.39, 33.28, 38.13, 36.25, 38.91, 38.9, 
                            36.85, 32.17, -2.07, 34.49, 35.7, 32.54, 37.91, 
                            37.35, 32.05, 38.03, 0.32, 33.87, 33.16, 34.74, 
                            32.47, 33.31, 34.54, 36.6, 36.09, 35.49, 370.51, 
                            37.33, 37.54, 33.32, 35.09, 33.08, 38.3, 34.32, 
                            37.01, 33.63, 36.35, 33.77, 33.74, 36.62, 36.74, 
                            37.76, 35.58, 38.76, 36.57, 37.05, 35.33, 36.41, 
                            35.54, 37.48, 36.22, 36.19, 36.43, 34.31, 34.85, 
                            38.76, 38.52, 38.02, 36.67, 32.51, 321.6, 37.82,
                            34.76, 33.55, 32.85, 32.99, 35.06]}, 
                   index = pd.date_range('2014-03-03 06:00','2014-03-06 22:00',freq='H'))

生成此图:

所以所有这些值都在 32 到 38 的范围内。我特意在 [0, 30, 38, 48, 82] 的索引上放置了非常大的数字,以在图表中创建峰值。

现在我试图在图表上查找如何执行所谓的“步进检测”,而我发现的唯一真正有用的答案是通过this question here,因此利用它我想出了这个整体代码...

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

df = pd.DataFrame({'price':[340.6, 35.66, 33.98, 38.67, 32.99, 32.04, 37.64, 
                            38.22, 37.13, 38.57, 32.4, 34.98, 36.74, 32.9,
                            32.52, 38.83, 33.9, 32.62, 38.93, 32.14, 33.09, 
                            34.25, 34.39, 33.28, 38.13, 36.25, 38.91, 38.9, 
                            36.85, 32.17, -2.07, 34.49, 35.7, 32.54, 37.91, 
                            37.35, 32.05, 38.03, 0.32, 33.87, 33.16, 34.74, 
                            32.47, 33.31, 34.54, 36.6, 36.09, 35.49, 370.51, 
                            37.33, 37.54, 33.32, 35.09, 33.08, 38.3, 34.32, 
                            37.01, 33.63, 36.35, 33.77, 33.74, 36.62, 36.74, 
                            37.76, 35.58, 38.76, 36.57, 37.05, 35.33, 36.41, 
                            35.54, 37.48, 36.22, 36.19, 36.43, 34.31, 34.85, 
                            38.76, 38.52, 38.02, 36.67, 32.51, 321.6, 37.82,
                            34.76, 33.55, 32.85, 32.99, 35.06]}, 
                   index = pd.date_range('2014-03-03 06:00','2014-03-06 22:00',freq='H'))
# df.plot()
# plt.show()

threshold = int(len(df['price']) * 0.75)
maxPeaks = argrelextrema(df['price'].values, np.greater, order=threshold)
minPeaks = argrelextrema(df['price'].values, np.less, order=threshold)

df2 = df.copy()
price_column_index = df2.columns.get_loc('price')
allPeaks = maxPeaks + minPeaks
for peakList in allPeaks:
    for peak in peakList:
        print(df2.iloc[peak]['price'])

但问题在于它似乎只返回了 30 和 82 的索引,并且它没有抓住索引 0 中的大值,也没有在负值下跌时抓住任何东西。虽然我很确定我错误地使用了这些方法。

现在,我了解对于这个特定问题,我可以只在列中查找大于或小于某个值的值,但我正在考虑处理 1000 多个条目的情况,其中处理“最低/最高正常值”无法准确确定,因此我只想要一个无论规模如何都能正常工作的尖峰检测。

所以我的问题如下:

1) 我一直在查看的有关步数检测的信息似乎非常密集,而且我很难理解。谁能提供有关如何处理这些“步骤检测”问题的一般规则?

2) 是否有任何公共图书馆可以更轻松地完成此类工作?如果有,它们是什么?

3) 如何使用 vanilla Python 实现相同的结果?我曾在许多不允许安装任何其他库的工作场所,强制制定不使用任何这些有用的外部库的解决方案,所以我想知道是否有某种公式/函数可以被写来达到类似的结果......

4) 从数据分析的角度来看,我可以使用哪些其他方法来处理此问题?我读过一些关于相关性、标准差的文章,但我实际上并不知道如何利用这些来识别尖峰在哪里......

编辑:另外,我发现this answer 以及使用 scipy 的 find_peaks 方法,但阅读它的文档我并不真正理解它们代表什么,以及传递的值来自哪里......对此的任何澄清都会不胜感激...

【问题讨论】:

  • 这很有趣,我刚刚使用 find_peaks 运行了您的数据,但在 df['price'][0] 处没有找到峰值

标签: python pandas numpy matplotlib scipy


【解决方案1】:

使用scipy.signal.find_peaks的解决方案

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


df = pd.DataFrame({'price':[340.6, 35.66, 33.98, 38.67, 32.99, 32.04, 37.64, 
                            38.22, 37.13, 38.57, 32.4,  34.98, 36.74, 32.9,
                            32.52, 38.83, 33.9,  32.62, 38.93, 32.14, 33.09, 
                            34.25, 34.39, 33.28, 38.13, 36.25, 38.91, 38.9, 
                            36.85, 32.17, -2.07, 34.49, 35.7, 32.54, 37.91, 
                            37.35, 32.05, 38.03, 0.32,  33.87, 33.16, 34.74, 
                            32.47, 33.31, 34.54, 36.6,  36.09, 35.49, 370.51, 
                            37.33, 37.54, 33.32, 35.09, 33.08, 38.3,  34.32, 
                            37.01, 33.63, 36.35, 33.77, 33.74, 36.62, 36.74, 
                            37.76, 35.58, 38.76, 36.57, 37.05, 35.33, 36.41, 
                            35.54, 37.48, 36.22, 36.19, 36.43, 34.31, 34.85, 
                            38.76, 38.52, 38.02, 36.67, 32.51, 321.6, 37.82,
                            34.76, 33.55, 32.85, 32.99, 35.06]}, 
                   index = pd.date_range('2014-03-03 06:00','2014-03-06 22:00',freq='H'))


x = df['price'].values
x = np.insert(x, 0, 0)              # added padding to catch any initial peaks in data

# for positive peaks
peaks, _ = find_peaks(x, height=50) # hieght is the threshold value
peaks = peaks - 1

print("The indices for peaks in the dataframe: ", peaks)
print(" ")
print("The values extracted from the dataframe")
print(df['price'][peaks])

# for negative peaks
x = x * - 1    
neg_peaks, _ = find_peaks(x, height=0) # hieght is the threshold value
neg_peaks = neg_peaks - 1

print(" ")
print("The indices for negative peaks in the dataframe: ", neg_peaks)
print(" ")
print("The values extracted from the dataframe")
print(df['price'][neg_peaks])

首先请注意,该算法的工作方式是在值之间进行比较。结果是数组的第一个值被忽略了,我怀疑这是您发布的解决方案的问题。

为了解决这个问题,我在0 位置用一个额外的0 填充了x 数组,你放在那里的值取决于你,

x = np.insert(x, 0, 0)

然后,算法会将要在数组中找到峰值的位置的索引返回到变量peaks

peaks, _ = find_peaks(x, height=50) # hieght is the threshold value

由于我添加了一个初始值,因此我必须从每个索引中减去 1,

peaks = peaks - 1

我现在可以使用这些索引从数据框中提取峰值,

print(df['price'][peaks])

【讨论】:

  • 感谢您的意见!虽然这个问题是虽然它解决了整个初始值问题,但它也没有拾取图表中的负峰值,而只返回正峰值。然后我是否必须想出另一个 find_peaks 线来找到这些负峰值?有没有其他方法可以想出一切(除了制作自己的功能)?
  • OK 已经添加了负峰的代码。它的过程相同,但我只是将数组乘以 -1
  • 您好,我已经查看了这个解决方案,虽然它回答了这个特定案例,但它不一定回答我最初的问题“你如何使它适用于所有人(或大多数)例?”。虽然没有“直接答案”,但我将对“使用 find_peaks 制作自己的函数是否更好。我可能会再等几周等待其他答案......
【解决方案2】:

关于不检测数据开头的峰值,您通常会定期对数据集重新采样,并将该样本的开头与前一个样本的结尾重叠一点点。数据上的这个“滑动窗口”可以帮助您完全避免这种情况,即在数据扫描之间的边界上丢失峰值。重叠应该大于您的信号检测宽度,在上面的示例中,它似乎是单个数据点。

例如,如果您正在查看一个月内的每日数据,分辨率为“1 天”,您将在上个月的最后一天开始扫描,以检测峰值发生在本月的第一天。

【讨论】:

    猜你喜欢
    • 2015-07-08
    • 2020-05-17
    • 2013-08-16
    • 2022-01-15
    • 2012-12-05
    • 1970-01-01
    • 2021-05-10
    • 1970-01-01
    相关资源
    最近更新 更多