Используйте представление и получите бесплатную среду выполнения! Расширить универсальные n-dim
массивы доn+1-dim
Представленный в NumPy1.10.0
, мы можем использовать numpy.broadcast_to
для простого создания 3D
представления во 2D
входном массиве. Преимущество заключается в отсутствии дополнительных накладных расходов на память и практически бесплатном времени выполнения. Это было бы важно в тех случаях, когда массивы большие и мы можем работать с представлениями. Кроме того, это будет работать с общими n-dim
случаями.
Я бы использовал слово stack
вместо copy
, поскольку читатели могли бы спутать его с копированием массивов, которое создает копии памяти.
Укладка по первой оси
Если мы хотим сложить ввод arr
по первой оси, решение np.broadcast_to
для создания 3D
представления будет -
np.broadcast_to(arr,(3,)+arr.shape) # N = 3 here
Укладка по третьей / последней оси
Чтобы сложить ввод arr
по третьей оси, решение для создания 3D
представления было бы -
np.broadcast_to(arr[...,None],arr.shape+(3,))
Если нам действительно нужна копия памяти, мы всегда можем добавить .copy()
туда. Следовательно, решения будут -
np.broadcast_to(arr,(3,)+arr.shape).copy()
np.broadcast_to(arr[...,None],arr.shape+(3,)).copy()
Вот как работает наложение для двух случаев, показано с информацией об их форме для примера случая:
# Create a sample input array of shape (4,5)
In [55]: arr = np.random.rand(4,5)
# Stack along first axis
In [56]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[56]: (3, 4, 5)
# Stack along third axis
In [57]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[57]: (4, 5, 3)
То же самое решение (а) будет работать для расширения n-dim
ввода для n+1-dim
просмотра вывода по первой и последней осям. Давайте рассмотрим несколько случаев более высокой тусклости -
Случай ввода 3D:
In [58]: arr = np.random.rand(4,5,6)
# Stack along first axis
In [59]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[59]: (3, 4, 5, 6)
# Stack along last axis
In [60]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[60]: (4, 5, 6, 3)
Случай ввода 4D:
In [61]: arr = np.random.rand(4,5,6,7)
# Stack along first axis
In [62]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[62]: (3, 4, 5, 6, 7)
# Stack along last axis
In [63]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[63]: (4, 5, 6, 7, 3)
и так далее.
Сроки
Давайте 2D
возьмем большой пример, получим тайминги и проверим, что вывод является файлом view
.
# Sample input array
In [19]: arr = np.random.rand(1000,1000)
Докажем, что предлагаемое решение действительно является взглядом. Мы будем использовать наложение по первой оси (результаты будут очень похожи для наложения по третьей оси) -
In [22]: np.shares_memory(arr, np.broadcast_to(arr,(3,)+arr.shape))
Out[22]: True
Давайте узнаем время, чтобы показать, что это практически бесплатно -
In [20]: %timeit np.broadcast_to(arr,(3,)+arr.shape)
100000 loops, best of 3: 3.56 µs per loop
In [21]: %timeit np.broadcast_to(arr,(3000,)+arr.shape)
100000 loops, best of 3: 3.51 µs per loop
Если говорить о представлении, то увеличение N
от 3
до 3000
ничего не меняет по таймингу, и оба они незначительны по таймингу. Следовательно, эффективен как по памяти, так и по производительности!
b[:,:,0]
,b[:,:,1]
иb[:,:,2]
. Каждый срез третьего измерения является копией исходного 2D-массива. Это не так очевидно, просто глядяprint(b)
.