【问题标题】:Peak detection in unevenly spaced timeseries不均匀时间序列中的峰值检测
【发布时间】:2020-10-08 22:20:03
【问题描述】:

我正在处理一个数据集,其中包含与datetime 相结合的度量,例如:

datetime value
2017-01-01 00:01:00,32.7
2017-01-01 00:03:00,37.8
2017-01-01 00:04:05,35.0
2017-01-01 00:05:37,101.1
2017-01-01 00:07:00,39.1
2017-01-01 00:09:00,38.9

我正在尝试检测并移除可能出现的潜在峰值,例如 2017-01-01 00:05:37,101.1 测量值。

到目前为止我发现的一些东西:

  • 这个数据集的时间间隔从 15 秒一直到 25 分钟不等,非常不均匀;
  • 无法事先确定峰的宽度
  • 峰高明显且明显偏离其他值
  • 时间步的归一化只应在去除异常值后进行,因为它们会干扰结果

  • 即使由于其他异常(例如,负值、平线),也“不可能”使它成为可能,即使没有它们,由于峰值也会产生错误的值;

  • find_peaks 期待均匀间隔的时间序列,因此 previous 解决方案不适用于我们拥有的不规则时间序列;
    • 在那个问题上,我忘了提到时间序列间隔不均匀的临界点。

我到处搜索,但找不到任何东西。实现将在 Python 中,但我愿意挖掘其他语言以获取逻辑。

【问题讨论】:

  • 您需要定义使阅读异常值的原因。也就是说,我看不出不均匀性有多大意义(更不用说关键了)。
  • 通过创建滚动窗口?在水流时间序列中,峰值被认为是 3 个连续测量之间的异常值,但是这 3 个测量需要在不到 5 分钟内发生,因为在物理上不可能有 25 m^3 的流量一分钟,然后下一分钟 110 m^3。 [...]
  • [...] 遗憾的是,传感器测量的时间不正确,要么在 50 秒内测量,要么可以一直到 25 分钟,如前所述。如果在滚动窗口中我们有 6 个度量,但时间是 [56,62,64,353,64,67] 秒,如果峰值位于第 4 位,那么这 5 分钟的损失可能是证明该高值合理的其他原因。
  • 啊。这些微小的细节使一切变得不同。如果我现在对您的理解正确,那么您对测量值的变化速度有一个先验知识。我将从if ((flow[i+1] - flow[i]) / (time[i+1] - time[i]) > threshold)
  • 这是只有您(作为拥有该领域知识的人)才能回答的问题。

标签: python pandas algorithm time-series language-agnostic


【解决方案1】:

我已在 github 上将此代码发布给将来遇到此问题或类似问题的任何人。

经过大量的反复试验,我认为我创造了一些可行的东西。使用@user58697 告诉我的内容,我设法创建了一个代码来检测阈值之间的每个峰值。

通过使用他/她解释if ((flow[i+1] - flow[i]) / (time[i+1] - time[i]) > threshold 的逻辑,我编写了以下代码:

首先读取.csv并解析日期,然后拆分成两个numpy数组:

dataset = pd.read_csv('https://raw.githubusercontent.com/MigasTigas/peak_removal/master/dataset_simple_example.csv', parse_dates=['date'])

dataset = dataset.sort_values(by=['date']).reset_index(drop=True).to_numpy()  # Sort and convert to numpy array

# Split into 2 arrays
values = [float(i[1]) for i in dataset]  # Flow values, in float
values = np.array(values)

dates = [i[0].to_pydatetime() for i in dataset]
dates = np.array(dates)

然后将(flow[i+1] - flow[i]) / (time[i+1] - time[i]) 应用于整个数据集:

flow = np.diff(values)
time = np.diff(dates).tolist()
time = np.divide(time, np.power(10, 9))

slopes = np.divide(flow, time) # (flow[i+1] - flow[i]) / (time[i+1] - time[i])
slopes = np.insert(slopes, 0, 0, axis=0) # Since we "lose" the first index, this one is 0, just for alignments

最后为了检测峰值,我们将数据减少到每个 x 秒的滚动窗口。这样我们就可以轻松检测到它们:

# ROLLING WINDOW
size = len(dataset)
rolling_window = []
rolling_window_indexes = []
RW = []
RWi = []
window_size = 240  # Seconds

dates = [i.to_pydatetime() for i in dataset['date']]
dates = np.array(dates)

# create the rollings windows
for line in range(size):
    limit_stamp = dates[line] + datetime.timedelta(seconds=window_size)
    for subline in range(line, size, 1):
        if dates[subline] <= limit_stamp:

            rolling_window.append(slopes[subline])  # Values of the slopes
            rolling_window_indexes.append(subline)  # Indexes of the respective values

        else:

            RW.append(rolling_window)
            if line != size: # To prevent clearing the last rolling window
                rolling_window = []

            RWi.append(rolling_window_indexes)
            if line != size:
                rolling_window_indexes = []

            break
else:
    # To get the last rolling window since it breaks before append
    RW.append(rolling_window)
    RWi.append(rolling_window_indexes)

在获得所有滚动窗口后,我们开始有趣:

t = 0.3  # Threshold
peaks = []

for index, rollWin in enumerate(RW):
    if rollWin[0] > t: # If the first value is greater of threshold
        top = rollWin[0] # Sets as a possible peak
        bottom = np.min(rollWin) # Finds the minimum of the peak

        if bottom < -t: # If less than the negative threshold
            bottomIndex = int(np.argmin(rollWin)) # Find it's index

            for peak in range(0, bottomIndex, 1): # Appends all points between the first index of the rolling window until the bottomIndex
                peaks.append(RWi[index][peak]) 

这段代码背后的想法是每个峰值都有一个上升和一个下降,如果两者都大于规定的阈值,那么它是一个异常峰值以及它们之间的所有峰值:

翻译成使用的真实数据集,发布在github

【讨论】:

    猜你喜欢
    • 2012-08-28
    • 2020-06-16
    • 2015-02-12
    • 2017-01-09
    • 2020-04-20
    • 2020-09-26
    相关资源
    最近更新 更多