Эффективный способ горизонтальной конкатенации без черепицы - PullRequest
3 голосов
/ 19 марта 2019

У меня есть два (больших) массива.В целях иллюстрации я использую простой пример ниже:

In [14]: arr1 = np.arange(32*512).reshape(32, 512)
In [15]: arr2 = np.arange(512).reshape(1, 512)

И я хотел сделать горизонтальную конкатенацию этих массивов (то есть конкатенацию по оси 1).Я придумал следующий подход для достижения этой цели:

In [16]: np.hstack([arr1, np.tile(arr2, (arr1.shape[0], 1))]).shape
Out[16]: (32, 1024)

Это работает как задумано.Тем не менее, я хотел бы знать, есть ли другие эффективные способы сделать это объединение без использования numpy.tile.Боюсь, что я бы взорвал свои требования к памяти, так как массивы действительно огромны.

Если возможно избежать этого дублирования строк (чтобы соответствовать размерам arr1), возможно, используя широковещательную передачу, тогда этобыло бы здорово!


PS Причина, по которой я хочу избежать этого копирования, заключается в линейном росте требований к памяти:

In [20]: arr2.nbytes
Out[20]: 4096

In [19]: np.tile(arr2, (arr1.shape[0], 1)).nbytes
Out[19]: 131072

In [22]: arr1.shape[0] * arr2.nbytes
Out[22]: 131072

1 Ответ

1 голос
/ 19 марта 2019

Вы можете предварительно распределить и использовать широковещательную рассылку, но это не сильно сэкономит (я бы ожидал, что пиковое использование памяти уменьшится примерно на четверть):

arr1 = np.arange(32*512).reshape(32, 512)
arr2 = np.arange(512).reshape(1, 512)
out = np.empty((32, 1024), arr1.dtype)
out[:, :512] = arr1
out[:, 512:] = arr2
out
#array([[    0,     1,     2, ...,   509,   510,   511],
#       [  512,   513,   514, ...,   509,   510,   511],
#       [ 1024,  1025,  1026, ...,   509,   510,   511],
#       ...,
#       [14848, 14849, 14850, ...,   509,   510,   511],
#       [15360, 15361, 15362, ...,   509,   510,   511],
#       [15872, 15873, 15874, ...,   509,   510,   511]])
...