2 回答

TA貢獻(xiàn)1900條經(jīng)驗(yàn) 獲得超5個(gè)贊
考慮到瘋狂的 FFT 優(yōu)化,我認(rèn)為 1D 卷積會(huì)很快完成你想要的事情:
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
請(qǐng)記住,這通常會(huì)為第一個(gè)和最后一個(gè) window_size//2 條目產(chǎn)生不準(zhǔn)確的值,因?yàn)樗鼈兊臐L動(dòng)平均值是使用零填充計(jì)算的,但是您可以通過在卷積之前填充您想要的值來更改此行為。
更新:添加了一個(gè)圖來與第二個(gè)答案進(jìn)行比較
卷積如何找到滾動(dòng)平均值?
本質(zhì)上,一維卷積可以被認(rèn)為是兩個(gè)數(shù)組的點(diǎn)積,因?yàn)橐粋€(gè)數(shù)組“滑動(dòng)”到另一個(gè)數(shù)組(實(shí)際上,相關(guān)性在技術(shù)上對(duì)于這種情況是正確的,但我現(xiàn)在不會(huì)深入討論)。為了獲得更好的想法,請(qǐng)考慮以下場(chǎng)景:
y = 1 2 3 4 5 6
x = 1 1 1
c = <convolution of y and x>
卷積數(shù)組的每個(gè)輸出索引都是“x”與其相同長(zhǎng)度窗口與 y 的點(diǎn)積。所以
c[0] = sum(y[0:3]*x)
c[1] = sum(y[1:4]*x)
c[2] = sum(y[2:5]*x)
...
現(xiàn)在,考慮 N 個(gè)數(shù)字的平均值就是 sum(numbers)/N 這一事實(shí)?;蛘撸?/p>
mean = sum(1/N * number)
結(jié)合我們?cè)谏厦鎸W(xué)到的關(guān)于卷積的知識(shí),讓 x = 1/len(x) 的每個(gè)元素:
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您可以保證卷積將在 上產(chǎn)生滾動(dòng)平均值y。
當(dāng)圖像中存在大量不需要的高頻噪聲時(shí),這在圖像處理中大量使用:
請(qǐng)注意,與您的一維數(shù)據(jù)類似,噪聲圖像中的尖銳“峰”和斑點(diǎn)被“舍入”了。
為什么窗口大小為 10?
老實(shí)說,我隨機(jī)選擇了窗口大小。實(shí)際上,這在很大程度上取決于您期望數(shù)據(jù)的噪聲程度以及您希望輸出看起來有多“平滑”。窗口大小越大,輸出看起來越平坦。根據(jù)提供的玩具編號(hào),似乎有一個(gè) 10 的窗口可以在y
不破壞信號(hào)的情況下壓平足夠的尖峰。

TA貢獻(xiàn)1785條經(jīng)驗(yàn) 獲得超8個(gè)贊
正如您在問題中提到的線性擬合的想法,我會(huì)尋求簡(jiǎn)單但相當(dāng)穩(wěn)健的解決方案,即擬合最佳線并簡(jiǎn)單地從數(shù)據(jù)中減去它以獲得去趨勢(shì)跟蹤:
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)
添加回答
舉報(bào)