2015-02-02 16 views
5

Sto cercando un modo veloce per calcolare una somma cumulativa, possibilmente utilizzando Numpy. Ecco il mio primo approccio:Arrotondamento rapido

def func1(M, w): 
    Rtn = np.zeros((M.shape[0], M.shape[1]-w+1)) 
    for i in range(M.shape[1]-w+1): 
     Rtn[:,i] = np.sum(M[:, i:w+i], axis=1) 
    return Rtn 

M = np.array([[0., 0., 0., 0., 0., 1., 1., 0., 1., 1., 1., 0., 0.], 
       [0., 0., 1., 0., 1., 0., 0., 0., 0., 0., 0., 1., 1.], 
       [1., 1., 0., 1., 0., 0., 0., 1., 0., 0., 0., 0., 0.]]) 

window_size = 4 
print func1(M, window_size) 

[[ 0. 0. 1. 2. 2. 3. 3. 3. 3. 2.] 
    [ 1. 2. 2. 1. 1. 0. 0. 0. 1. 2.] 
    [ 3. 2. 1. 1. 1. 1. 1. 1. 0. 0.]] 

ho voluto evitare che la finestra (/ sum) da essere rifatta nel ciclo e, auspicabilmente, rendere molto più veloce così mi si avvicinò con la seguente funzione che limita la somma al solo primo e dell'ultimo elemento della finestra di laminazione:

def func2(M, w): 
    output = np.zeros((M.shape[0], M.shape[1]-w+1)) 
    sum = np.sum(M[:, 0:w], axis=1) 
    output[:,0] = sum 

    for i in range(w, M.shape[1]): 
     sum = sum + M[:,i]- M[:,i-w] 
     output[:,i-w+1] = sum 
    return output 

Ma con mia sorpresa, func2 è appena più veloce di func1:

In [251]: 
M = np.random.randint(2, size=3000).reshape(3, 1000) 

window_size = 100 
%timeit func1(M, window_size) 
10 loops, best of 3: 20.9 ms per loop 

In [252]: 
%timeit func2(M, w) 
10 loops, best of 3: 15.5 ms per loop 

mi manca qualcosa qui? Ragazzi, sapete qualcosa di meglio, intendo un modo più veloce per raggiungere questo obiettivo?

+2

Dal esecuzione somma == media mobile, Eventuali duplicati: http: // StackOverflow .com/questions/14313510/moving-average-function-on-numpy-scipy –

+0

Oltre al divisione parte, ma altrimenti sì – YXD

+1

Non stai prendendo la somma effettiva. Stai cercando una ** finestra scorrevole **, non una somma parziale. – smci

risposta

9

Adattato da @ risposta di Jaime qui: https://stackoverflow.com/a/14314054/553404

import numpy as np 

def rolling_sum(a, n=4) : 
    ret = np.cumsum(a, axis=1, dtype=float) 
    ret[:, n:] = ret[:, n:] - ret[:, :-n] 
    return ret[:, n - 1:] 

M = np.array([[0., 0., 0., 0., 0., 1., 1., 0., 1., 1., 1., 0., 0.], 
       [0., 0., 1., 0., 1., 0., 0., 0., 0., 0., 0., 1., 1.], 
       [1., 1., 0., 1., 0., 0., 0., 1., 0., 0., 0., 0., 0.]]) 

print(rolling_sum(M)) 

uscita

[[ 0. 0. 1. 2. 2. 3. 3. 3. 3. 2.] 
[ 1. 2. 2. 1. 1. 0. 0. 0. 1. 2.] 
[ 3. 2. 1. 1. 1. 1. 1. 1. 0. 0.]] 

Tempi

In [7]: %timeit rolling_sum(M, 4) 
100000 loops, best of 3: 7.89 µs per loop 

In [8]: %timeit func1(M, 4) 
10000 loops, best of 3: 70.4 µs per loop 

In [9]: %timeit func2(M, 4) 
10000 loops, best of 3: 54.1 µs per loop 
+0

Fantastico. Solo un pignolo, devi prendere la somma reale (running_sum (M)) ' – smci

+0

Sei sicuro? Non l'ho capito dalla domanda. – YXD

+0

? In tal caso, OP sta cercando una ** finestra scorrevole **, non una somma parziale – smci