当前位置: 代码迷 >> python >> Pandas 数据帧图的步进/尖峰检测故障?
  详细解决方案

Pandas 数据帧图的步进/尖峰检测故障?

热度:115   发布时间:2023-07-16 10:58:15.0

我目前正在尝试学习如何通过 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] 的索引上放置了非常大的数字,以在图中创建尖峰。

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

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) 如何使用普通 Python 实现相同的结果? 我去过许多不允许安装任何其他库的工作场所,迫使解决方案不使用任何这些有用的外部库,所以我想知道是否有某种公式/函数可以被写入以达到类似的结果......

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

编辑:另外,我也使用 scipy 的find_peaks方法找到了,但阅读它的文档我真的不明白它们代表什么,以及传递的值来自哪里......对此的任何澄清将不胜感激......

使用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])

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

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

  相关解决方案