[英]Detrending a time-series of a multi-dimensional array without the for loops
我有一個3D陣列,該陣列具有地球表面上每個網格點的海氣碳通量時間序列(模型輸出)。 我想刪除時間序列中的趨勢(線性)。 我碰到了這段代碼:
from matplotlib import mlab
for x in xrange(40):
for y in xrange(182):
cflux_detrended[:, x, y] = mlab.detrend_linear(cflux[:, x, y])
我可以通過不使用for循環來加快速度嗎?
Scipy有很多信號處理工具。 使用scipy.signal.detrend()
將刪除沿數據軸的線性趨勢。 從文檔中看來,整個數據集的線性趨勢似乎將從每個網格點的時間序列中減去。
import scipy.signal
cflux_detrended = scipy.signal.detrend(cflux, axis=0)
使用scipy.signal
將獲得與使用原始帖子中的方法相同的結果。 使用Josef的detrend_separate()
函數也將返回相同的結果。
這是使用numpy.linalg.lstsq的兩個版本。 此版本使用np.vander創建任何多項式趨勢。
警告:除示例外,未經測試。
我認為這樣的事情將被添加到scikits.statsmodels中,后者也沒有用於降趨勢的多元版本。 對於常見趨勢情況,我們可以使用scikits.statsmodels OLS,我們還可以獲取所有結果統計信息以進行估計。
# -*- coding: utf-8 -*-
"""Detrending multivariate array
Created on Fri Dec 02 15:08:42 2011
Author: Josef Perktold
http://stackoverflow.com/questions/8355197/detrending-a-time-series-of-a-multi-dimensional-array-without-the-for-loops
I should also add the multivariate version to statsmodels
"""
import numpy as np
import matplotlib.pyplot as plt
def detrend_common(y, order=1):
'''detrend multivariate series by common trend
Paramters
---------
y : ndarray
data, can be 1d or nd. if ndim is greater then 1, then observations
are along zero axis
order : int
degree of polynomial trend, 1 is linear, 0 is constant
Returns
-------
y_detrended : ndarray
detrended data in same shape as original
'''
nobs = y.shape[0]
shape = y.shape
y_ = y.ravel()
nobs_ = len(y_)
t = np.repeat(np.arange(nobs), nobs_ /float(nobs))
exog = np.vander(t, order+1)
params = np.linalg.lstsq(exog, y_)[0]
fittedvalues = np.dot(exog, params)
resid = (y_ - fittedvalues).reshape(*shape)
return resid, params
def detrend_separate(y, order=1):
'''detrend multivariate series by series specific trends
Paramters
---------
y : ndarray
data, can be 1d or nd. if ndim is greater then 1, then observations
are along zero axis
order : int
degree of polynomial trend, 1 is linear, 0 is constant
Returns
-------
y_detrended : ndarray
detrended data in same shape as original
'''
nobs = y.shape[0]
shape = y.shape
y_ = y.reshape(nobs, -1)
kvars_ = len(y_)
t = np.arange(nobs)
exog = np.vander(t, order+1)
params = np.linalg.lstsq(exog, y_)[0]
fittedvalues = np.dot(exog, params)
resid = (y_ - fittedvalues).reshape(*shape)
return resid, params
nobs = 30
sige = 0.1
y0 = 0.5 * np.random.randn(nobs,4,3)
t = np.arange(nobs)
y_observed = y0 + t[:,None,None]
for detrend_func, name in zip([detrend_common, detrend_separate],
['common', 'separate']):
y_detrended, params = detrend_func(y_observed, order=1)
print '\n\n', name
print 'params for detrending'
print params
print 'std of detrended', y_detrended.std() #should be roughly sig=0.5 (var of y0)
print 'maxabs', np.max(np.abs(y_detrended - y0))
print 'observed'
print y_observed[-1]
print 'detrended'
print y_detrended[-1]
print 'original "true"'
print y0[-1]
plt.figure()
for i in range(4):
for j in range(3):
plt.plot(y0[:,i,j], 'bo', alpha=0.75)
plt.plot(y_detrended[:,i,j], 'ro', alpha=0.75)
plt.title(name + ' detrending: blue - original, red - detrended')
plt.show()
自從尼古拉斯指出scipy.signal.detrend。 我的分離趨勢與scipy.signal.detrend基本相同,具有更少的選擇(無軸或中斷)或不同的選擇(具有多項式順序)。
>>> res = signal.detrend(y_observed, axis=0)
>>> (res - y0).var()
0.016931858083279336
>>> (y_detrended - y0).var()
0.01693185808327945
>>> (res - y_detrended).var()
8.402584948582852e-30
我認為對舊列表的理解最簡單:
cflux_detrended = np.array([[mlab.detrend_linear(t) for t in kk] for kk in cflux.T])
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.