问题描述
我目前正在尝试学习如何通过 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
方法找到了,但阅读它的文档我真的不明白它们代表什么,以及传递的值来自哪里......对此的任何澄清将不胜感激......
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])
2楼
在不检测数据开头的峰值方面,您通常会定期对数据集重新采样,并将此样本的开头与前一个样本的结尾重叠一点。 这个数据上的“滑动窗口”可以帮助您避免这种情况,即在数据扫描之间的边界上丢失峰。 重叠应该大于您的信号检测宽度,在上面的示例中,它似乎是单个数据点。
例如,如果您正在查看一个月内的每日数据,分辨率为“1 天”,那么您将在上个月的最后一天开始扫描,以检测发生在这个月的第一天。