Наверное, самый чистый способ - использовать np.repeat
:
a = np.array([[1, 2], [1, 2]])
print(a.shape)
# (2, 2)
# indexing with np.newaxis inserts a new 3rd dimension, which we then repeat the
# array along, (you can achieve the same effect by indexing with None, see below)
b = np.repeat(a[:, :, np.newaxis], 3, axis=2)
print(b.shape)
# (2, 2, 3)
print(b[:, :, 0])
# [[1 2]
# [1 2]]
print(b[:, :, 1])
# [[1 2]
# [1 2]]
print(b[:, :, 2])
# [[1 2]
# [1 2]]
Сказав это, вы часто можете вообще избежать повторения массивов, используя широковещательную рассылку . Например, скажем, я хотел добавить (3,)
вектор:
c = np.array([1, 2, 3])
к a
. Я мог бы скопировать содержимое a
3 раза в третьем измерении, затем c
дважды скопировать содержимое как в первом, так и во втором измерениях, так что оба моих массива были (2, 2, 3)
, а затем вычислить их сумму. Однако сделать это намного проще и быстрее:
d = a[..., None] + c[None, None, :]
Здесь a[..., None]
имеет форму (2, 2, 1)
и c[None, None, :]
форму (1, 1, 3)
*. Когда я вычисляю сумму, результат "транслируется" по размерам размера 1, давая мне результат формы (2, 2, 3)
:
print(d.shape)
# (2, 2, 3)
print(d[..., 0]) # a + c[0]
# [[2 3]
# [2 3]]
print(d[..., 1]) # a + c[1]
# [[3 4]
# [3 4]]
print(d[..., 2]) # a + c[2]
# [[4 5]
# [4 5]]
Широковещательная рассылка - очень мощный метод, поскольку он позволяет избежать дополнительных накладных расходов, связанных с созданием повторяющихся копий входных массивов в памяти.
* Хотя я включил их для ясности, None
индексы в c
фактически не нужны - вы также можете сделать это a[..., None] + c
, т.е. транслировать (2, 2, 1)
массив против (3,)
массива. Это связано с тем, что если один из массивов имеет меньше измерений, чем другой, тогда должны быть совместимы только конечные измерения двух массивов. Приведем более сложный пример:
a = np.ones((6, 1, 4, 3, 1)) # 6 x 1 x 4 x 3 x 1
b = np.ones((5, 1, 3, 2)) # 5 x 1 x 3 x 2
result = a + b # 6 x 5 x 4 x 3 x 2
b[:,:,0]
,b[:,:,1]
иb[:,:,2]
. Каждый срез третьего измерения является копией исходного 2D-массива. Это не так очевидно, просто глядяprint(b)
.np.newaxis
это просто псевдонимNone
Другой способ - использовать
numpy.dstack
. Предположим, вы хотите повторить матрицуa
num_repeats
раз:Хитрость заключается в том, чтобы обернуть матрицу
a
списком из одного элемента, а затем использовать*
оператор для дублирования элементов в этом спискеnum_repeats
раз.Например, если:
Это повторяет массив
[1 2; 1 2]
5 раз в третьем измерении. Чтобы проверить (в IPython):В конце мы видим, что форма матрицы состоит
2 x 2
из 5 срезов в третьем измерении.источник
reshape
? Быстрее? дает такую же структуру? Это определенно аккуратнее.Используйте представление и получите бесплатную среду выполнения! Расширить универсальные
n-dim
массивы доn+1-dim
Представленный в NumPy
1.10.0
, мы можем использоватьnumpy.broadcast_to
для простого создания3D
представления во2D
входном массиве. Преимущество заключается в отсутствии дополнительных накладных расходов на память и практически бесплатном времени выполнения. Это было бы важно в тех случаях, когда массивы большие и мы можем работать с представлениями. Кроме того, это будет работать с общимиn-dim
случаями.Я бы использовал слово
stack
вместоcopy
, поскольку читатели могли бы спутать его с копированием массивов, которое создает копии памяти.Укладка по первой оси
Если мы хотим сложить ввод
arr
по первой оси, решениеnp.broadcast_to
для создания3D
представления будет -Укладка по третьей / последней оси
Чтобы сложить ввод
arr
по третьей оси, решение для создания3D
представления было бы -Если нам действительно нужна копия памяти, мы всегда можем добавить
.copy()
туда. Следовательно, решения будут -Вот как работает наложение для двух случаев, показано с информацией об их форме для примера случая:
То же самое решение (а) будет работать для расширения
n-dim
ввода дляn+1-dim
просмотра вывода по первой и последней осям. Давайте рассмотрим несколько случаев более высокой тусклости -Случай ввода 3D:
Случай ввода 4D:
и так далее.
Сроки
Давайте
2D
возьмем большой пример, получим тайминги и проверим, что вывод является файломview
.Докажем, что предлагаемое решение действительно является взглядом. Мы будем использовать наложение по первой оси (результаты будут очень похожи для наложения по третьей оси) -
Давайте узнаем время, чтобы показать, что это практически бесплатно -
Если говорить о представлении, то увеличение
N
от3
до3000
ничего не меняет по таймингу, и оба они незначительны по таймингу. Следовательно, эффективен как по памяти, так и по производительности!источник
Отредактируйте @ Mr.F, чтобы сохранить порядок размеров:
источник
B.shape
распечатки(N, 2, 2)
для любого значенияN
. Если вы транспонируетеB
с,B.T
он соответствует ожидаемому результату.B[0], B[1],...
даст вам правильный фрагмент, который я буду утверждать и скажу, что его легче набирать, чем использоватьB[:,:,0], B[:,:,1]
и т. Д.B[:,:,i]
, к чему я привык.Теперь это также можно получить с помощью np.tile следующим образом:
источник
Вот пример трансляции, который делает именно то, что было запрошено.
Затем
b*a
желаемый результат и(b*a)[:,:,0]
производитarray([[1, 2],[1, 2]])
, то есть оригиналa
, как делает(b*a)[:,:,1]
и т. Д.источник