2 回答

TA貢獻1900條經驗 獲得超5個贊
考慮到瘋狂的 FFT 優化,我認為 1D 卷積會很快完成你想要的事情:
import numpy as np
from scipy.signal import convolve
window_size = 10
y = np.array([-10.5, -2.0, 5.0, -3.0, 4.0, 9.5, 18.0, 14.5, 11.0, 13.5, 25.0, 21.5, 7.5, 5.5, 3.5, 10.5, 7.0, 3.5, 1.5, 16.0, 20.0, 22.5, 20.5, 33.5, 27.0, 38.5, 29.0, 27.0, 28.0, 24.5, 24.0, 29.5, 39.5])
# Pad with zeros for entries before/after the window size
y_rolling_mean = convolve(y, np.ones(window_size)/window_size, 'same')
y_without_mean = y - y_rolling_mean
請記住,這通常會為第一個和最后一個 window_size//2 條目產生不準確的值,因為它們的滾動平均值是使用零填充計算的,但是您可以通過在卷積之前填充您想要的值來更改此行為。
更新:添加了一個圖來與第二個答案進行比較
卷積如何找到滾動平均值?
本質上,一維卷積可以被認為是兩個數組的點積,因為一個數組“滑動”到另一個數組(實際上,相關性在技術上對于這種情況是正確的,但我現在不會深入討論)。為了獲得更好的想法,請考慮以下場景:
y = 1 2 3 4 5 6
x = 1 1 1
c = <convolution of y and x>
卷積數組的每個輸出索引都是“x”與其相同長度窗口與 y 的點積。所以
c[0] = sum(y[0:3]*x)
c[1] = sum(y[1:4]*x)
c[2] = sum(y[2:5]*x)
...
現在,考慮 N 個數字的平均值就是 sum(numbers)/N 這一事實?;蛘撸?/p>
mean = sum(1/N * number)
結合我們在上面學到的關于卷積的知識,讓 x = 1/len(x) 的每個元素:
y = 1 2 3 4 5 6
x = 1/3 1/3 1/3
c[0] = 1/3*y[0] + 1/3*y[1] + 1/3*y[2] = mean(y[0:3])
c[1] = 1/3*y[1] + 1/3*y[2] + 1/3*y[3] = mean(y[1:4]
...
整潔的!與特殊形式的 x 向量卷積的副作用是該范圍的平均值!因此,通過將 x 選擇為 be,np.ones(window_size)/window_size您可以保證卷積將在 上產生滾動平均值y。
當圖像中存在大量不需要的高頻噪聲時,這在圖像處理中大量使用:
請注意,與您的一維數據類似,噪聲圖像中的尖銳“峰”和斑點被“舍入”了。
為什么窗口大小為 10?
老實說,我隨機選擇了窗口大小。實際上,這在很大程度上取決于您期望數據的噪聲程度以及您希望輸出看起來有多“平滑”。窗口大小越大,輸出看起來越平坦。根據提供的玩具編號,似乎有一個 10 的窗口可以在y
不破壞信號的情況下壓平足夠的尖峰。

TA貢獻1785條經驗 獲得超8個贊
正如您在問題中提到的線性擬合的想法,我會尋求簡單但相當穩健的解決方案,即擬合最佳線并簡單地從數據中減去它以獲得去趨勢跟蹤:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(len(y))
coefs = np.polyfit(x, y, 1)
line = coefs[1] + x*coefs[0]
detrended = y-line
fig, ax = plt.subplots(1)
ax.plot(y)
ax.plot(line)
ax.plot(detrended)
添加回答
舉報