2017-03-17 16 views
2

次MAD機能のローリングバージョンを作成する方法numpyのバージョン(絶対平均偏差)

from numpy import mean, absolute 

def mad(data, axis=None): 
    return mean(absolute(data - mean(data, axis)), axis) 

このコードは、私がパンダにnumpyの変換現時点でthis question

への答えでありますこの関数を適用し、結果をnumpyに戻す

pandasDataFrame.rolling(window=90).apply(mad) 

しかし、これは大きなデータフレームでは非効率的です。同じ関数のための回転ウィンドウをループなしで取得して同じ結果を返すにはどうすればいいですか?

+0

それほど効率的ではありませんか? – kmario23

+0

私の頭の中には何か他の意味があります:)ありがとう – RaduS

答えて

3

ここでベクトル化numpyのアプローチだ -

# From this post : http://stackoverflow.com/a/40085052/3293881 
def strided_app(a, L, S): # Window len = L, Stride len/stepsize = S 
    nrows = ((a.size-L)//S)+1 
    n = a.strides[0] 
    return np.lib.stride_tricks.as_strided(a, shape=(nrows,L), strides=(S*n,n)) 

# From this post : http://stackoverflow.com/a/14314054/3293881 by @Jaime 
def moving_average(a, n=3) : 
    ret = np.cumsum(a, dtype=float) 
    ret[n:] = ret[n:] - ret[:-n] 
    return ret[n - 1:]/n 

def mad_numpy(a, W): 
    a2D = strided_app(a,W,1) 
    return np.absolute(a2D - moving_average(a,W)[:,None]).mean(1) 

ランタイムテスト - 愚かパンダソリューションあそこ32x+

In [617]: data = np.random.randint(0,9,(10000)) 
    ...: df = pd.DataFrame(data) 
    ...: 

In [618]: pandas_out = pd.rolling_apply(df,90,mad).values.ravel() 
In [619]: numpy_out = mad_numpy(data,90) 

In [620]: np.allclose(pandas_out[89:], numpy_out) # Nans part clipped 
Out[620]: True 

In [621]: %timeit pd.rolling_apply(df,90,mad) 
10 loops, best of 3: 111 ms per loop 

In [622]: %timeit mad_numpy(data,90) 
100 loops, best of 3: 3.4 ms per loop 

In [623]: 111/3.4 
Out[623]: 32.64705882352941 

巨大なスピードアップが!

関連する問題