2017-03-17 2 views
2

Wie eine Roll Version der folgenden MAD Funktion machenNumpy Version von Roll MAD (mittlere absolute Abweichung)

from numpy import mean, absolute 

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

Dieser Code ist eine Antwort auf this question

Im Moment bin numpy zu Pandas konvertieren dann diese Funktion anwenden, dann das Ergebnis zurück konvertieren

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

numpy aber dies ist auf größerem Datenrahmen ineffizient. Wie bekomme ich ein rollendes Fenster für die gleiche Funktion in numpy ohne Looping und gebe das gleiche Ergebnis?

+0

nicht so ineffizient? – kmario23

+0

gut, weißt du, in meinem Kopf meinte ich etwas anderes :) danke – RaduS

Antwort

3

Hier ist ein vektorisiert NumPy Ansatz -

# 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) 

Runtime Test -

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 

Huge 32x+ Speedup dort über die durchgeknallten Pandas Lösung!

Verwandte Themen