簡體   English   中英

在沒有for循環的情況下對多維數組的時間序列進行趨勢除

[英]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.

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