Numpy: разница между np.repeat и np.broadcast_to - PullRequest
0 голосов
/ 09 января 2020

1 ° Почему следующий код возвращает False? Я думал, что np.broadcast_to увеличит размерность массива так же, как np.repeat.

2 ° Могу ли я воспроизвести результат, заданный np.repeat с np.broadcast_to?

import numpy as np
n = 100
d = 10
A = np.random.uniform(size=(n,d))
np.all(np.broadcast_to(A.reshape(n,1,d),(n,d-1,d))==np.repeat(A,d-1).reshape(n,d-1,d))

3 ° Более в целом, для данного массива A формы (n, d ), как я могу воспроизвести np.repeat(A,k).reshape((n,k,d)) с np.broadcast_to?

Ответы [ 2 ]

2 голосов
/ 09 января 2020

Здесь происходит ряд вещей, и было бы проще работать с массивом, содержащим небольшое количество значений флагов, для выявления проблем. Вот пример, с которым легко работать:

arr = np.array([[1, 2, 1, 2], [3, 4, 3, 4]]) # n = 2, d = 4

Давайте посмотрим, что делает broadcast_to:

>>> A.reshape(n, 1, d)
array([[[1, 2, 1, 2]],
       [[3, 4, 3, 4]]])
>>> arr.broadcast_to(_, (n, d - 1, d))
array([[[1, 2, 1, 2],
        [1, 2, 1, 2],
        [1, 2, 1, 2]],
       [[3, 4, 3, 4],
        [3, 4, 3, 4],
        [3, 4, 3, 4]]])

Вы можете получить функционально аналогичные массивы с tile, stack и concatenate. Основное отличие состоит в том, что broadcast_to делает , а не копирует данные в новом измерении. Вместо этого он корректирует шаг так, чтобы массив имел правильный размер (что приводит к неожиданному поведению, если вы неосторожны, например, при записи в буфер):

  • np.tile(arr.reshape(n, 1, d), (1, d - 1, 1))
  • np.stack([arr] * (d - 1), axis=1)
  • np.concatenate([arr.reshape(n, 1, d)] * (d - 1), axis=1)

Теперь давайте взглянем на repeat:

>>> np.repeat(arr, d - 1)
array([1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 3, 3, 3, 4, 4, 4])

Это плоский массив, каждый элемент которого повторяется d - 1 раз. Очевидно, что изменение формы здесь не будет таким же, как у широковещательной / плиточной версии:

>>> _.reshape(n, d - 1, d)
array([[[1, 1, 1, 2],
        [2, 2, 1, 1],
        [1, 2, 2, 2]],
       [[3, 3, 3, 4],
        [4, 4, 3, 3],
        [3, 4, 4, 4]]])

Очевидно, что поэлементное повторение не идентично трансляции. Однако, если бы вы использовали правильное ключевое слово axis, вы могли бы получить правильный результат:

>>> np.repeat(arr.reshape(n, 1, d), d - 1, axis=1)
array([[[1, 2, 1, 2],
        [1, 2, 1, 2],
        [1, 2, 1, 2]],

       [[3, 4, 3, 4],
        [3, 4, 3, 4],
        [3, 4, 3, 4]]])

Если бы вы хотели go другим способом, и данные были бы короче строк, вы можете просто заново интерпретировать размеры, используя комбинацию transpose и reshape:

>>> np.broadcast_to(arr.reshape(n, 1, d), (n, d - 1, d)).transpose([0, 2, 1]).reshape(n, d - 1, d)
array([[[1, 1, 1, 2],
        [2, 2, 1, 1],
        [1, 2, 2, 2]],
       [[3, 3, 3, 4],
        [4, 4, 3, 3],
        [3, 4, 4, 4]]])

Вот пошаговое руководство по преобразованию:

>>> arr.reshape(n, 1, d)
array([[[1, 2, 1, 2]],
       [[3, 4, 3, 4]]])
>>> np.broadcast_to(_, (n, d - 1, d))
array([[[1, 2, 1, 2],
        [1, 2, 1, 2],
        [1, 2, 1, 2]],
       [[3, 4, 3, 4],
        [3, 4, 3, 4],
        [3, 4, 3, 4]]])
>>> _.transpose(0, 2, 1)
array([[[1, 1, 1],
        [2, 2, 2],
        [1, 1, 1],
        [2, 2, 2]],
       [[3, 3, 3],
        [4, 4, 4],
        [3, 3, 3],
        [4, 4, 4]]])
>>> _.reshape(n, d - 1, d)
array([[[1, 1, 1, 2],
        [2, 2, 1, 1],
        [1, 2, 2, 2]],
       [[3, 3, 3, 4],
        [4, 4, 3, 3],
        [3, 4, 4, 4]]])
1 голос
/ 09 января 2020

np.broadcast_to дает вам повтор в массиве , в то время как np.repeat дает вам поэтапное повторное поведение, см. Примеры в документации [1] и [2] . Чтобы добиться равных выходных данных в этом случае, вы можете изменить изменение формы следующим образом:

import numpy as np
n = 100
d = 10
A = np.random.uniform(size=(n,d))

A_bc = np.broadcast_to(A.reshape(n*d, 1), (n*d, d-1)).reshape(n, d-1, d)
A_rp = np.repeat(A, d-1).reshape(n, d-1, d)

np.all(A_rp == A_bc)
# True

Примечание: хотя timeit указывает, что опция broadcast_to немного быстрее, я не уверен, что она на самом деле более эффективно с памятью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...