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

Python, как заполнить массив numpy с нулями

Я хочу знать, как я могу разместить 2D-массив numpy с нулями, используя python 2.6.6 с numpy версии 1.5.0. Сожалею! Но это мои ограничения. Поэтому я не могу использовать np.pad. Например, я хочу наложить a на нули, чтобы его форма соответствовала b. Причина, по которой я хочу сделать это, я могу сделать:

b-a

такое, что

>>> a
array([[ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.]])
>>> b
array([[ 3.,  3.,  3.,  3.,  3.,  3.],
       [ 3.,  3.,  3.,  3.,  3.,  3.],
       [ 3.,  3.,  3.,  3.,  3.,  3.],
       [ 3.,  3.,  3.,  3.,  3.,  3.]])
>>> c
array([[1, 1, 1, 1, 1, 0],
       [1, 1, 1, 1, 1, 0],
       [1, 1, 1, 1, 1, 0],
       [0, 0, 0, 0, 0, 0]])

Единственный способ, которым я могу думать об этом, - это добавить, однако это кажется довольно уродливым. есть ли более чистое решение, возможно, используя b.shape?

Изменить, Спасибо вам за ответ MSeiferts. Мне пришлось немного почистить его, и вот что я получил:

def pad(array, reference_shape, offsets):
    """
    array: Array to be padded
    reference_shape: tuple of size of ndarray 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
    """

    # Create an array of zeros with the reference shape
    result = np.zeros(reference_shape)
    # 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
4b9b3361

Ответ 1

Очень просто, вы создаете массив, содержащий нули, используя опорную форму:

result = np.zeros(b.shape)
# actually you can also use result = np.zeros_like(b) 
# but that also copies the dtype not only the shape

а затем вставьте массив, в котором он вам нужен:

result[:a.shape[0],:a.shape[1]] = a

и вуаля вы добавили его:

print(result)
array([[ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.]])

Вы также можете сделать это более общим, если вы определяете, где должен быть вставлен ваш верхний левый элемент

result = np.zeros_like(b)
x_offset = 1  # 0 would be what you wanted
y_offset = 1  # 0 in your case
result[x_offset:a.shape[0]+x_offset,y_offset:a.shape[1]+y_offset] = a
result

array([[ 0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  1.,  1.,  1.,  1.,  1.],
       [ 0.,  1.,  1.,  1.,  1.,  1.],
       [ 0.,  1.,  1.,  1.,  1.,  1.]])

но будьте осторожны, чтобы у вас не было смещений больше, чем разрешено. Например, для x_offset = 2 это не будет выполнено.


Если у вас есть произвольное количество измерений, вы можете определить список срезов для вставки исходного массива. Мне было интересно немного поиграть и создать функцию заполнения, которая может накладывать (со смещением) арбитальный массив, если массив и ссылка имеют одинаковое количество измерений, а смещения не слишком велики.

def pad(array, reference, offsets):
    """
    array: Array to be padded
    reference: Reference array with the desired shape
    offsets: list of offsets (number of elements must be equal to the dimension of the array)
    """
    # Create an array of zeros with the reference shape
    result = np.zeros(reference.shape)
    # Create a list of slices from offset to offset + shape in each dimension
    insertHere = [slice(offset[dim], offset[dim] + array.shape[dim]) for dim in range(a.ndim)]
    # Insert the array in the result at the specified offsets
    result[insertHere] = a
    return result

И некоторые тестовые примеры:

import numpy as np

# 1 Dimension
a = np.ones(2)
b = np.ones(5)
offset = [3]
pad(a, b, offset)

# 3 Dimensions

a = np.ones((3,3,3))
b = np.ones((5,4,3))
offset = [1,0,0]
pad(a, b, offset)

Ответ 2

NumPy 1.7.0 (когда был добавлен numpy.pad) сейчас довольно стар (он был выпущен в 2013 году), поэтому, несмотря на то, что в вопросе был задан способ без использования этой функции, я подумал, что было бы полезно узнать, как этого можно добиться с помощью numpy.pad.

Это на самом деле довольно просто:

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

В этом случае я использовал 0 как значение по умолчанию для mode='constant'. Но это также можно указать, передав его явно:

>>> np.pad(a, [(0, 1), (0, 1)], mode='constant', constant_values=0)
array([[ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.]])

На всякий случай второй аргумент ([(0, 1), (0, 1)]) выглядит сбивающим с толку: каждому элементу списка (в данном случае кортежу) соответствует измерение, а элемент в нем представляет заполнение до (первый элемент) и после (второй элемент). Так:

[(0, 1), (0, 1)]
         ^^^^^^------ padding for second dimension
 ^^^^^^-------------- padding for first dimension

  ^------------------ no padding at the beginning of the first axis
     ^--------------- pad with one "value" at the end of the first axis.

В этом случае отступы для первой и второй оси идентичны, так что можно просто передать 2 кортежа:

>>> np.pad(a, (0, 1), mode='constant')
array([[ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.]])

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

>>> np.pad(a, 1, mode='constant')
array([[ 0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  1.,  1.,  1.,  1.,  1.,  0.],
       [ 0.,  1.,  1.,  1.,  1.,  1.,  0.],
       [ 0.,  1.,  1.,  1.,  1.,  1.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.]])

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

>>> np.pad(a, [(1, ), (2, )], mode='constant')
array([[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  1.,  1.,  1.,  1.,  1.,  0.,  0.],
       [ 0.,  0.,  1.,  1.,  1.,  1.,  1.,  0.,  0.],
       [ 0.,  0.,  1.,  1.,  1.,  1.,  1.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]])

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

>>> np.pad(a, [1, 2], mode='constant')
array([[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  1.,  1.,  1.,  1.,  1.,  0.,  0.],
       [ 0.,  1.,  1.,  1.,  1.,  1.,  0.,  0.],
       [ 0.,  1.,  1.,  1.,  1.,  1.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]])

Здесь NumPy думает, что вы хотите заполнить все оси 1 элементом до и 2 элементами после каждой оси! Даже если вы намеревались заполнить 1 элемент по оси 1 и 2 элемента по оси 2.

Я использовал списки кортежей для заполнения, заметьте, что это просто "мое соглашение", вы также можете использовать списки списков или кортежей кортежей или даже кортежей массивов. NumPy просто проверяет длину аргумента (или, если он не имеет длины) и длину каждого элемента (или, если он имеет длину)!

Ответ 3

Я понимаю, что ваша основная проблема заключается в том, что вам нужно вычислить d=b-a, но ваши массивы имеют разные размеры. Нет необходимости в промежуточном дополнении c

Вы можете решить это без заполнения:

import numpy as np

a = np.array([[ 1.,  1.,  1.,  1.,  1.],
              [ 1.,  1.,  1.,  1.,  1.],
              [ 1.,  1.,  1.,  1.,  1.]])

b = np.array([[ 3.,  3.,  3.,  3.,  3.,  3.],
              [ 3.,  3.,  3.,  3.,  3.,  3.],
              [ 3.,  3.,  3.,  3.,  3.,  3.],
              [ 3.,  3.,  3.,  3.,  3.,  3.]])

d = b.copy()
d[:a.shape[0],:a.shape[1]] -=  a

print d

Вывод:

[[ 2.  2.  2.  2.  2.  3.]
 [ 2.  2.  2.  2.  2.  3.]
 [ 2.  2.  2.  2.  2.  3.]
 [ 3.  3.  3.  3.  3.  3.]]

Ответ 4

В случае, если вам нужно добавить забор 1с в массив:

>>> mat = np.zeros((4,4), np.int32)
>>> mat
array([[0, 0, 0, 0],
       [0, 0, 0, 0],
       [0, 0, 0, 0],
       [0, 0, 0, 0]])
>>> mat[0,:] = mat[:,0] = mat[:,-1] =  mat[-1,:] = 1
>>> mat
array([[1, 1, 1, 1],
       [1, 0, 0, 1],
       [1, 0, 0, 1],
       [1, 1, 1, 1]])