Я пытаюсь заменить все значения границы моего n-мерного массива на False
. До сих пор я видел, что numpy предоставляет np.pad
, который позволяет мне увеличивать массив во всех измерениях с помощью произвольного массива. Есть ли эквивалент, чтобы сделать обратное и «сжать» массив, обрезав границы?
Вот пример в 2D, который я хотел бы расширить до произвольного размера:
import numpy as np
nd_array = np.random.randn(100,100)>0 # Just to have a random bool array, but the same would apply with floats, for example
cut_array = nd_array[1:-1, 1:-1] # This is what I would like to generalize to arbitrary dimension
padded_array = np.pad(cut_array, pad_width=1, mode='constant', constant_values=False)
Конечно, если есть более простой способ изменить значения границ в произвольном размере, это также будет оценено.
Вы можете использовать np.delete, чтобы удалить последний столбец (индекс 99 в вашем примере).
import numpy as np
nd_array = np.random.randn(100, 100) > 0
cut_array = np.delete(nd_array, 99, 1) # Delete 100th column (index 99)
padded_array = np.pad(cut_array, pad_width=1, mode='constant', constant_values=False)
Я бы не стал использовать подход сначала обрезки, а затем заполнения, потому что таким образом вы перемещаете много памяти.
Вместо этого я бы явно установил индексы границы на желаемое значение:
import numpy as np
border_value = False
nd_array = np.random.randn(100,100) > 0
# Iterate over all dimensions of `nd_array`
for dim in range(nd_array.ndim):
# Make current dimension the first dimension
array_moved = np.moveaxis(nd_array, dim, 0)
# Set border values in the current dimension
array_moved[0] = border_value
array_moved[-1] = border_value
# We do not even need to move the current dimension
# back to its original position, as `np.moveaxis()`
# provides a view into the original data, thus by
# altering the values of `array_moved`, we also
# alter the values of `nd_array`. So we are done.
Обратите внимание, что np.moveaxis()
— довольно дешевая операция, так как она только корректирует шаги массива (в нашем случае для создания array_moved
), поэтому фактические данные массива не перемещаются.
Примечание. Я думаю, что ответ Саймона лучше подходит для этого конкретного вопроса, но я оставляю метод для фактического удаления границ вместо их замены, на случай, если это кому-то понадобится.
Ответ TheOneMusic предлагает хорошую идею с использованием np.delete
, но реализация в этом ответе не дает желаемого ответа ни для одного измерения. Однако мы можем использовать эту идею, создав рекурсивную функцию, которая удаляет последний и первый элементы на заданной оси и на всех осях перед ней:
import numpy as np
def remove_borders(array, last_axis=None):
if last_axis is None:
last_axis = len(array.shape)
new_array = np.delete(array, [0,-1], axis=last_axis)
if last_axis>0:
new_array = remove_borders(new_array, last_axis-1)
return new_array
И тогда остальная часть скрипта будет выглядеть примерно так:
nd_array = np.random.randn(100,100) > 0 # Just to have a random bool array, but the same would apply with floats, for example
cut_array = remove_borders(nd_array)
padded_array = np.pad(cut_array, pad_width=1, mode='constant', constant_values=False)
Кажется, это работает для произвольного размера, хотя он не оптимизирован и, вероятно, будет бороться с большими массивами большого размера.
Я не знал о
np.moveaxis
, это звучит очень полезно. Буду иметь в виду, спасибо!