簡體   English   中英

python中的時間序列分割

[英]time-series segmentation in python

我正在嘗試對時間序列數據進行分段,如圖所示。 我有很多來自傳感器的數據,這些數據中的任何一個都可以有不同數量的孤立峰區域。 在這個圖中,我有 3 個。 我想要一個函數,它將時間序列作為輸入並返回等長的分段部分。

我最初的想法是有一個滑動窗口來計算振幅的相對變化。 由於具有峰值的窗口將具有相對較高的變化,因此我可以為相對變化定義某個閾值,這將有助於我采用具有孤立峰值的窗口。 然而,這在選擇閾值時會產生問題,因為相對變化對數據中的噪聲非常敏感。

有什么建議?

圖片 : 所需的時間序列數據分段帶軸的圖

為此,您需要從噪聲中找出信號。

  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()

輸出:

紅線 = 所有數據的平均值

綠線 - 頂部和底部噪聲邊界

橙色線 - 選定的峰值數據

在此處輸入圖片說明

1,這取決於你想如何定義一個“區域”,但看起來你只是感覺而不是嚴格的定義。 如果你對要剪出什么樣的片有很清楚的定義,你可以嘗試一些方法,比如“匹配過濾器”

2,您可能想要檢測絕對幅度的峰值。 如果不起作用,請嘗試一階差分絕對幅度的峰值,甚至二階。

3,很難處理這樣的嘈雜數據。 我的建議是在選擇部分之前進行過濾(在未過濾的數據上)。 過濾將為您提供平滑的峰值,以便可以通過微分符號的變化來檢測峰值的位置。 對於過濾,請先嘗試“低通濾波器”。 如果它不起作用,我還建議“希爾伯特-黃變換”。

*, 看起來您正在使用 matlab。 提到的方法都包含在matlab中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM