2013-02-18 4 views
20

Я люблю то, как питон обрабатывает свопы переменных: a, b, = b, aсвоп ломтика Numpy массивов

, и я хотел бы использовать эту функцию, чтобы поменять местами между массивами, а не только по одному, но число из них (без использования временной переменной). Это не то, что я ожидал (я надеялся, что обе записи вдоль третьего измерения будет поменять местами для обоих):

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] 

Кто-нибудь есть идеи? Конечно, я всегда могу ввести дополнительную переменную, но мне было интересно, был ли более элегантный способ сделать это.

+0

Мой любимый подход здесь: http://stackoverflow.com/a/4857981/786902 (продвинутая нарезка) –

ответ

17

Python правильно интерпретирует код, как если бы вы использовали дополнительные переменные, так что код подкачки эквивалентен:

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

Однако даже этот код не поменять значения правильно! Это связано с тем, что Numpy slices не копируют данные, они создают представления в существующие данные. Копии выполняются только в том месте, где назначены срезы, но при замене копия без промежуточного буфера уничтожает ваши данные. Вот почему вам нужна не только дополнительная переменная, но и дополнительный буфер numpy, о котором общий синтаксис Python ничего не знает. Например, это работает, как ожидалось:

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

Я предполагаю 'sp.copy' должен быть' np.copy', если вы используете 'импорт numpy как np'. – Holger

+0

@Holger вопрос был отредактирован; он первоначально импортировал «scipy as sp». Теперь я отредактировал ответ, чтобы отразить редактирование. – user4815162342

1

user4815162342's answer действительно «правильный» один. Но если вы действительно после однострочника, то подумайте:

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

Это, однако, значительно менее эффективно:

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 

(но обратите внимание на заметку о «медленном запуске» .. если вы попытаетесь называть% timeit с помощью «-n 1 -r 1», вы увидите более сопоставимые результаты - хотя мое решение все еще будет на 50% медленнее - показывая, что да, кеширование влияет на тайминги)

+1

Нет ответа «Принято» по этому вопросу – portforwardpodcast

+1

@portforwardpodcast right! Исправлена. –

4

Я считаю это самым простым:

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

Время сравнения:

%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

Это будет работать.

a[:,0,0], b[:, 0, 0] = b[:, 0, 0].copy(), a[:, 0, 0].copy() 
Смежные вопросы