Подтвердить что ты не робот

Хорошие способы "расширить" numpy ndarray?

Есть ли хорошие способы "расширить" numpy ndarray? Скажем, у меня такой ndarray:

[[1 2]
 [3 4]]

И я хочу, чтобы каждая строка содержала больше элементов, заполняя нули:

[[1 2 0 0 0]
 [3 4 0 0 0]]

Я знаю, что для этого нужно иметь какие-то способы грубой силы (скажем, построить более массивный массив с нулями, а затем скопировать элементы из старых меньших массивов), просто интересно, существуют ли способы pythonic для этого. Пробовал numpy.reshape, но не работал:

import numpy as np
a = np.array([[1, 2], [3, 4]])
np.reshape(a, (2, 5))

Numpy жалуется, что: ValueError: total size of new array must be unchanged

4b9b3361

Ответ 1

Существуют трюки индекса r_ и c_.

>>> import numpy as np
>>> a = np.array([[1, 2], [3, 4]])
>>> z = np.zeros((2, 3), dtype=a.dtype)
>>> np.c_[a, z]
array([[1, 2, 0, 0, 0],
       [3, 4, 0, 0, 0]])

Если это критический код производительности, вы можете предпочесть использовать эквивалентный np.concatenate, а не трюки индекса.

>>> np.concatenate((a,z), axis=1)
array([[1, 2, 0, 0, 0],
       [3, 4, 0, 0, 0]])

Есть также np.resize и np.ndarray.resize, но у них есть некоторые ограничения (из-за того, как numpy выводит данные в память), поэтому читайте docstring на этих. Вы, вероятно, обнаружите, что лучше просто конкатенировать.

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

Ответ 2

Вы можете использовать numpy.pad, как показано ниже:

>>> import numpy as np
>>> a=[[1,2],[3,4]]
>>> np.pad(a, ((0,0),(0,3)), mode='constant', constant_values=0)
array([[1, 2, 0, 0, 0],
       [3, 4, 0, 0, 0]])

Здесь np.pad говорит: "Возьмите массив a и добавьте 0 строк выше него, 0 строк ниже него, 0 столбцов слева от него и 3 столбца справа от него. Заполните эти столбцы constant, указанный constant_values".

Ответ 3

Просто, чтобы быть ясным: нет никакого "хорошего" способа расширения массива NumPy, поскольку массивы NumPy не расширяемы. Как только массив определен, пространство, которое он занимает в памяти, комбинация числа его элементов и размера каждого элемента, является фиксированным и не может быть изменено. Единственное, что вы можете сделать, это создать новый массив и заменить некоторые его элементы элементами исходного массива.

Для удобства доступно множество функций (функция np.concatenate и ее np.*stack ярлыки np.column_stack, подпрограммы индексов np.r_ и np.c_...), но есть только такие: удобные функции. Некоторые из них оптимизированы на уровне C (np.concatenate и другие, я думаю), некоторые из них не являются.

Обратите внимание, что ничего не происходит с вашим первоначальным предложением создать большой массив "вручную" (возможно, заполненный нулями) и заполнить его самим исходным массивом. Возможно, было бы более понятно, что более сложные решения.

Ответ 4

Вы должны использовать np.column_stack или append

import numpy as np

p = np.array([ [1,2] , [3,4] ])

p = np.column_stack( [ p , [ 0 , 0 ],[0,0] ] )

p
Out[277]: 
array([[1, 2, 0, 0],
       [3, 4, 0, 0]])

Добавление кажется скорее быстрым:

timeit np.column_stack( [ p , [ 0 , 0 ],[0,0] ] )
10000 loops, best of 3: 61.8 us per loop

timeit np.append(p, [[0,0],[0,0]],1)
10000 loops, best of 3: 48 us per loop

И сравнение с np.c_ и np.hstack [append все еще кажется самым быстрым]:

In [295]: z=np.zeros((2, 2), dtype=a.dtype)

In [296]: timeit np.c_[a, z]
10000 loops, best of 3: 47.2 us per loop

In [297]: timeit np.append(p, z,1)
100000 loops, best of 3: 13.1 us per loop

In [305]: timeit np.hstack((p,z))
10000 loops, best of 3: 20.8 us per loop

и np.concatenate [это даже немного быстрее, чем append]:

In [307]: timeit np.concatenate((p, z), axis=1)
100000 loops, best of 3: 11.6 us per loop

Ответ 5

Простой способ:

# what you want to expand
x = np.ones((3, 3))

# expand to what shape 
target = np.zeros((6, 6))

# do expand
target[:x.shape[0], :x.shape[1]] = x

# print target
array([[ 1.,  1.,  1.,  0.,  0.,  0.],
       [ 1.,  1.,  1.,  0.,  0.,  0.],
       [ 1.,  1.,  1.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.]])

Функциональный способ:

заимствовать из fooobar.com/questions/217224/... с небольшими изменениями.

def pad(array, reference_shape, offsets=None):
    """
    array: Array to be padded
    reference_shape: tuple of size of narray to create
    offsets: list of offsets (number of elements must be equal to the dimension of the array)
    will throw a ValueError if offsets is too big and the reference_shape cannot handle the offsets
    """

    if not offsets:
        offsets = np.zeros(array.ndim, dtype=np.int32)

    # Create an array of zeros with the reference shape
    result = np.zeros(reference_shape, dtype=np.float32)
    # Create a list of slices from offset to offset + shape in each dimension
    insertHere = [slice(offsets[dim], offsets[dim] + array.shape[dim]) for dim in range(array.ndim)]
    # Insert the array in the result at the specified offsets
    result[insertHere] = array
    return result

Ответ 6

Существуют также аналогичные методы, такие как np.vstack, np.hstack, np.dstack. Мне они нравятся над np.concatente, поскольку он дает понять, какое измерение "расширяется".

temp = np.array([[1, 2], [3, 4]])
np.hstack((temp, np.zeros((2,3))))

легко запомнить, потому что первая ось первой оси вертикальна, поэтому vstack расширяет первую ось, а вторая ось - горизонтально, так что hstack.