Обрезать ломтики массивов 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()