2013-02-18 16 views
20

Uwielbiam sposób pyton jest obsługa zamiany zmiennych a, b, = b, aswap plastry tablic numpy

i chciałbym, aby korzystać z tej funkcji, aby zamienić wartości między tablicami, a także, nie tylko jeden na raz, ale ich liczba (bez użycia zmiennej tymczasowej). To nie to, co się spodziewałem (miałem nadzieję, obie pozycje wzdłuż trzeciego wymiaru zamieniłbym dla obu):

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] 

Czy ktoś ma pomysł? Oczywiście zawsze mogę wprowadzić dodatkową zmienną, ale zastanawiałem się, czy istnieje bardziej elegancki sposób robienia tego.

+0

Moim ulubionym sposobem jest tutaj: http://stackoverflow.com/a/4857981/786902 (zaawansowane krojenie) –

Odpowiedz

17

Python poprawnie interpretuje kod jakby użyto dodatkowych zmiennych, więc kod zamiana jest równoznaczne z:

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

Jednak nawet ten kod nie zamienić wartości poprawnie! Dzieje się tak, ponieważ Numpy slices nie skrzętnie kopiuje danych, tworzą widoki na istniejące dane. Kopie są wykonywane tylko w momencie przypisania plasterków, ale podczas zamiany kopia bez bufora pośredniego niszczy dane. Dlatego potrzebna jest nie tylko dodatkowa zmienna, ale także dodatkowy bufor liczbowy, o którym ogólna składnia Pythona nic nie wie. Na przykład działa to zgodnie z oczekiwaniami:

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

Chyba 'sp.copy' powinno być' np.copy', jeśli używasz 'import numpy jako np.. – Holger

+0

@Holger pytanie zostało zredagowane; pierwotnie zaimportował 'scipy jako sp'. Teraz zredagowałem odpowiedź, aby odzwierciedlić edycję. – user4815162342

1

user4815162342's answer jest rzeczywiście "prawidłowy". Ale jeśli jesteś naprawdę po jednej wkładki, a następnie rozważyć to:

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

Jest to jednak znacznie mniej skuteczny:

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 

(nie zauważyć notatkę o „najwolniejszym biegu” .. jeśli spróbujesz wywołać% timeit za pomocą "-n 1 -r 1", zobaczysz bardziej porównywalne wyniki - chociaż z moim rozwiązaniem nadal będzie ono ~ 50% wolniejsze - pokazując, że tak, buforowanie wpływa na taktowanie)

+1

Nie ma odpowiedzi "Zaakceptowany" w tym pytaniu – portforwardpodcast

+1

@portforwardpodcast right! Naprawiony. –

4

Uważam to za najprostsze:

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

porównanie Czas:

%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

to będzie działać.

a[:,0,0], b[:, 0, 0] = b[:, 0, 0].copy(), a[:, 0, 0].copy() 
Powiązane problemy