Я хочу знать, как можно заполнить двумерный массив 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
?
Edit, спасибо за ответ 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
padded = np.zeros(b.shape)
padded[tuple(slice(0,n) for n in a.shape)] = a
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)]
) может сбивать с толку: каждый элемент списка (в данном случае кортеж) соответствует измерению, а элемент в нем представляет собой заполнение до (первый элемент) и после (второй элемент). Так:В этом случае отступы для первой и второй оси идентичны, поэтому можно также просто передать 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 и двумя элементами для оси 2.
Я использовал списки кортежей для заполнения, обратите внимание, что это просто «мое соглашение», вы также можете использовать списки списков или кортежи кортежей или даже кортежи массивов. NumPy просто проверяет длину аргумента (или если она не имеет длины) и длину каждого элемента (или если она имеет длину)!
источник
mode='constant'
является разумным значением по умолчанию, поэтому заполнение нулями может быть достигнуто без необходимости использования каких-либо дополнительных ключевых слов, что приводит к немного более читаемому коду.Я понимаю, что ваша основная проблема в том, что вам нужно рассчитывать,
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.]]
источник
Если вам нужно добавить в массив забор из единиц:
>>> 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]])
источник
Я знаю, что немного опоздал с этим, но в случае, если вы хотите выполнить относительное заполнение (также называемое краевым заполнением), вот как вы можете его реализовать. Обратите внимание, что самый первый экземпляр присваивания приводит к заполнению нулями, поэтому вы можете использовать его как для заполнения нулями, так и для относительного заполнения (здесь вы копируете значения краев исходного массива в заполненный массив).
def replicate_padding(arr): """Perform replicate padding on a numpy array.""" new_pad_shape = tuple(np.array(arr.shape) + 2) # 2 indicates the width + height to change, a (512, 512) image --> (514, 514) padded image. padded_array = np.zeros(new_pad_shape) #create an array of zeros with new dimensions # perform replication padded_array[1:-1,1:-1] = arr # result will be zero-pad padded_array[0,1:-1] = arr[0] # perform edge pad for top row padded_array[-1, 1:-1] = arr[-1] # edge pad for bottom row padded_array.T[0, 1:-1] = arr.T[0] # edge pad for first column padded_array.T[-1, 1:-1] = arr.T[-1] # edge pad for last column #at this point, all values except for the 4 corners should have been replicated padded_array[0][0] = arr[0][0] # top left corner padded_array[-1][0] = arr[-1][0] # bottom left corner padded_array[0][-1] = arr[0][-1] # top right corner padded_array[-1][-1] = arr[-1][-1] # bottom right corner return padded_array
Анализ сложности:
Оптимальным решением для этого является метод numpy's pad. После усреднения для 5 прогонов np.pad с относительным заполнением
8%
лучше, чем функция, определенная выше. Это показывает, что это довольно оптимальный метод для относительного заполнения и заполнения нулями.#My method, replicate_padding start = time.time() padded = replicate_padding(input_image) end = time.time() delta0 = end - start #np.pad with edge padding start = time.time() padded = np.pad(input_image, 1, mode='edge') end = time.time() delta = end - start print(delta0) # np Output: 0.0008790493011474609 print(delta) # My Output: 0.0008130073547363281 print(100*((delta0-delta)/delta)) # Percent difference: 8.12316715542522%
источник