【问题标题】:time-series segmentation in pythonpython中的时间序列分割
【发布时间】:2020-05-18 02:31:05
【问题描述】:

我正在尝试对时间序列数据进行分段,如图所示。我有很多来自传感器的数据,这些数据中的任何一个都可以有不同数量的孤立峰区域。在这个图中,我有 3 个。我想要一个将时间序列作为输入并返回相等长度的分段部分的函数。

我最初的想法是有一个滑动窗口来计算幅度的相对变化。由于具有峰值的窗口会有相对较高的变化,因此我可以为相对变化定义某个阈值,这将有助于我采用具有孤立峰值的窗口。但是,这会在选择阈值时产生问题,因为相对变化对数据中的噪声非常敏感。

有什么建议吗?

【问题讨论】:

  • 你能发布输入数据吗?分段是指从泥炭开始到峰值结束的数据?没有轴有单位的图没有价值。
  • 是的,我想要从峰值开始到结束的数据。我已经添加了带有轴的图形。我真的不知道如何添加输入数据。它是一个 .txt 文件。我在这里看不到任何附加它们的选项。
  • 您可以生成带有噪声的随机测试数据来模拟您的数据。您需要如何存储这些数据段?在 csv 中?
  • 保存数据段并不重要。我只需要首先从连续数据中找到一种方法来分割它们。

标签: python time-series segment


【解决方案1】:

为此,您需要从噪声中找出信号。

  1. 获取信号的平均值并添加一些多人游戏,在噪声的顶部和底部放置边界 - 绿色虚线
  2. 找到低于噪声底部的峰值 -> 数组 2 组数据
  3. 在噪声之上找到峰值 -> 数组 2 组数据
  4. 获取底部第一个峰值的最小索引和第一个峰值顶部的最大索引以找到第一个峰值范围
  5. 获取第二个顶部峰值的最小索引和第二个峰值底部的最大索引以找到第二个峰值范围

代码中的一些描述。使用这种方法,您可以找到其他峰。 您需要手动输入的一件事是告诉程序峰值之间的x 值,以便将数据拆分为多个部分。

请参见图表了解摘要。

import numpy as np
from matplotlib import pyplot as plt


# create noise data
def function(x, noise):
    y = np.sin(7*x+2) + noise
    return y

def function2(x, noise):
    y = np.sin(6*x+2) + noise
    return y


noise = np.random.uniform(low=-0.3, high=0.3, size=(100,))
x_line0 = np.linspace(1.95,2.85,100)
y_line0 = function(x_line0, noise)
x_line = np.linspace(0, 1.95, 100)
x_line2 = np.linspace(2.85, 3.95, 100)
x_pik = np.linspace(3.95, 5, 100)
y_pik = function2(x_pik, noise)
x_line3 = np.linspace(5, 6, 100)

# concatenate noise data
x = np.linspace(0, 6, 500)
y = np.concatenate((noise, y_line0, noise, y_pik, noise), axis=0)

# plot data
noise_band = 1.1
top_noise = y.mean()+noise_band*np.amax(noise)
bottom_noise = y.mean()-noise_band*np.amax(noise)
fig, ax = plt.subplots()
ax.axhline(y=y.mean(), color='red', linestyle='--')
ax.axhline(y=top_noise, linestyle='--', color='green')
ax.axhline(y=bottom_noise, linestyle='--', color='green')
ax.plot(x, y)

# split data into 2 signals
def split(arr, cond):
  return [arr[cond], arr[~cond]]

# find bottom noise data indexes
botom_data_indexes = np.argwhere(y < bottom_noise)
# split by visual x value
splitted_bottom_data = split(botom_data_indexes, botom_data_indexes < np.argmax(x > 3))

# find top noise data indexes
top_data_indexes = np.argwhere(y > top_noise)
# split by visual x value
splitted_top_data = split(top_data_indexes, top_data_indexes < np.argmax(x > 3))

# get first signal range
first_signal_start = np.amin(splitted_bottom_data[0])
first_signal_end = np.amax(splitted_top_data[0])

# get x index of first signal
x_first_signal = np.take(x, [first_signal_start, first_signal_end])
ax.axvline(x=x_first_signal[0], color='orange')
ax.axvline(x=x_first_signal[1], color='orange')

# get second signal range
second_signal_start = np.amin(splitted_top_data[1])
second_signal_end = np.amax(splitted_bottom_data[1])

# get x index of first signal
x_second_signal = np.take(x, [second_signal_start, second_signal_end])
ax.axvline(x=x_second_signal[0], color='orange')
ax.axvline(x=x_second_signal[1], color='orange')

plt.show()

输出:

红线 = 所有数据的平均值

绿线 - 顶部和底部噪声边界

橙色线 - 选定的峰值数据

【讨论】:

  • @AashishShah 不客气!如果你接受我的回答会很好:)
【解决方案2】:

1,这取决于你想如何定义一个“区域”,但看起来你只是有感觉而不是严格的定义。如果你对要剪出什么样的片子有非常明确的定义,你可以试试“匹配滤镜”之类的方法

2,您可能想要检测绝对幅度的峰值。如果不起作用,请尝试一阶差分的绝对幅度峰值,甚至二阶。

3,很难处理这样的嘈杂数据。我的建议是在您选择部分之前进行过滤(关于未过滤的数据)。过滤将为您提供平滑的峰值,以便可以通过导数符号的变化来检测峰值的位置。对于过滤,请先尝试“低通滤波器”。如果不行,我还建议“希尔伯特-黄变换”。

*, 看起来你正在使用 matlab。上述方法均包含在matlab中。

【讨论】:

  • 数据来自加速度传感器。它记录随时间变化的加速度读数。峰值表明在给定时间对传感器施加了一些力。在上图中,施加了 3 次负载,并有一定的时间延迟。这个时间延迟随着不同的数据集而变化。所以,我想对每个记录的峰值单独进行一些处理。为此,我必须先拆分它们。
猜你喜欢
  • 2012-04-02
  • 2021-10-28
  • 2018-06-05
  • 2018-09-10
  • 2012-02-21
  • 2017-02-11
  • 2020-05-20
  • 2021-05-10
  • 2016-05-25
相关资源
最近更新 更多