2013-02-18 15 views
20

Amo il modo in pitone sta gestendo swap di variabili: a, b, = b, afette Swap di array NumPy

e vorrei usare questa funzionalità per scambiare valori tra array così, non solo uno alla volta, ma a numero di loro (senza utilizzare una variabile temporanea). Questo non fa quello che mi aspettavo (speravo entrambe le voci lungo la terza dimensione potrebbe scambiare per entrambi):

import numpy as np 
a = np.random.randint(0, 10, (2, 3,3)) 
b = np.random.randint(0, 10, (2, 5,5)) 
# display before 
a[:,0, 0] 
b[:,0,0] 
a[:,0,0], b[:, 0, 0] = b[:, 0, 0], a[:,0,0] #swap 
# display after 
a[:,0, 0] 
b[:,0,0] 

Qualcuno ha un'idea? Naturalmente posso sempre introdurre una variabile aggiuntiva, ma mi chiedevo se esistesse un modo più elegante per farlo.

+0

Il mio approccio preferito è qui: http://stackoverflow.com/a/4857981/786902 (affettare avanzato) –

risposta

17

Python interpreta correttamente il codice come se si è utilizzato variabili aggiuntive, in modo che il codice di scambio è equivalente a:

t1 = b[:,0,0] 
t2 = a[:,0,0] 
a[:,0,0] = t1 
b[:,0,0] = t2 

Tuttavia, anche questo codice non scambiare correttamente i valori! Questo perché Numpy slices non copia impazientemente i dati, ma crea viste in dati esistenti. Le copie vengono eseguite solo nel punto in cui vengono assegnate le fette, ma durante lo swap, la copia senza un buffer intermedio distrugge i dati. Questo è il motivo per cui è necessario non solo una variabile aggiuntiva, ma un buffer addizionale numpy, che la sintassi generale di Python non può sapere nulla. Ad esempio, questo funziona come previsto:

t = np.copy(a[:,0,0]) 
a[:,0,0] = b[:,0,0] 
b[:,0,0] = t 
+0

Credo 'sp.copy' dovrebbe essere' np.copy', se si utilizza 'import numpy come np'. – Holger

+0

@Holger la domanda è stata modificata; originariamente importava 'scipy as sp'. Ora ho modificato la risposta per riflettere la modifica. – user4815162342

1

user4815162342's answer corrisponda effettivamente a quello "giusto". Ma se siete veramente dopo una battuta, quindi prendere in considerazione questo:

a[arange(2),0,0], b[arange(2), 0, 0] = b[arange(2), 0, 0], a[arange(2),0,0] #swap 

Questo è comunque molto meno efficienti:

In [12]: %timeit a[arange(2),0,0], b[arange(2), 0, 0] = b[arange(2), 0, 0], a[arange(2),0,0] 
10000 loops, best of 3: 32.2 µs per loop 

In [13]: %timeit t = np.copy(a[:,0,0]); a[:,0,0] = b[:,0,0]; b[:,0,0] = t 
The slowest run took 4.14 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 13.3 µs per loop 

(a meno di notare la nota su "la corsa più lento" .. . se provi a chiamare% timeit con "-n 1 -r 1", vedrai risultati più comparabili - sebbene la mia soluzione sia ancora ~ 50% più lenta - dimostrando che sì, la cache sta influenzando i tempi)

+1

Non c'è una risposta "accettata" su questa domanda – portforwardpodcast

+1

@portforwardpodcast giusto! Fisso. –

4

Lo trovo il più semplice:

a[:,0,0], b[:, 0, 0] = b[:, 0, 0], a[:, 0, 0].copy() #swap 

confronto Tempo:

%timeit a[:,0,0], b[:, 0, 0] = b[:, 0, 0], a[:, 0, 0].copy() #swap 
The slowest run took 10.79 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 1.75 µs per loop 

%timeit t = np.copy(a[:,0,0]); a[:,0,0] = b[:,0,0]; b[:,0,0] = t 
The slowest run took 10.88 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 2.68 µs per loop 
-2

Questo funzionerà.

a[:,0,0], b[:, 0, 0] = b[:, 0, 0].copy(), a[:, 0, 0].copy()