Обрезать ломтики массивов Numpy

Мне нравится, как python обрабатывает свопы переменных:   a, b, = b, a

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

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]

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

Ответ 1

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

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

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

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

Ответ 2

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

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

Ответ 3

user4815162342 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% медленнее - демонстрируя, что да, кеширование влияет на тайминги)

Ответ 4

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

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