2011-09-23 8 views
6

Sto cercando di scrivere una funzione che esegue un'operazione matematica su un array e restituisce il risultato. Un esempio semplificato potrebbe essere:Alterare array di uscita funzione NumPy in atto

def original_func(A): 
    return A[1:] + A[:-1] 

Per accelerazione e ad evitare di allocare una nuova matrice di uscita per ciascuna chiamata di funzione, desidero avere la matrice di output come argomento, e modificare in posizione:

def inplace_func(A, out): 
    out[:] = A[1:] + A[:-1] 

Tuttavia, quando si chiama queste due funzioni nel modo seguente,

A = numpy.random.rand(1000,1000) 
out = numpy.empty((999,1000)) 

C = original_func(A) 

inplace_func(A, out) 

la funzione originale sembra essere due volte più veloce come funzione sul posto. Come può essere spiegato? La funzione sul posto non dovrebbe essere più veloce poiché non deve allocare memoria?

risposta

5

Io penso che la risposta è la seguente:

In entrambi i casi, di calcolare A[1:] + A[:-1], e in entrambi i casi, è effettivamente creare una matrice intermedia.

Ciò che accade nel secondo caso, tuttavia, è che è esplicitamente copiare l'intero array di nuova assegnazione in una memoria riservata. Copiare un array di questo tipo richiede all'incirca lo stesso tempo dell'operazione originale, quindi in effetti raddoppia il tempo.

Riassumendo-up, nel primo caso, si fa:

compute A[1:] + A[:-1] (~10ms) 

Nel secondo caso, si fa

compute A[1:] + A[:-1] (~10ms) 
copy the result into out (~10ms) 
+1

Per quanto riguarda una soluzione: I * * pensare che dovrete fare i loop da soli per evitare gli array intermedi descritti nella risposta di Olivier. O forse qualcosa come http://code.google.com/p/numexpr/ può aiutarti? Anche questa [domanda] (http://stackoverflow.com/questions/2937669/linear-combinations-in-python-numpy) sembra pertinente. – gspr

+0

Penso che si possa evitare l'array intermedio in questo modo: 'out [:] = A [1:]; out + = A [: - 1] "Ovviamente il tuo algo attuale probabilmente sarà più difficile da ottimizzare. Cerco ovviamente di evitare i loop a tutti i costi. Ci sono spesso cose creative che puoi fare con accumuli e ufuncs .. – Paul

-1

Sono d'accordo con Oliver spiegazione. Se si desidera eseguire l'operazione sul posto, è necessario eseguire il loop sull'array manualmente. Questo sarà molto più lento, ma se hai bisogno di velocità puoi ricorrere a Cython che ti dà la velocità di una pura implementazione in C.