Удалить границы n-мерного массива numpy

Я пытаюсь заменить все значения границы моего 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)

Конечно, если есть более простой способ изменить значения границ в произвольном размере, это также будет оценено.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
0
87
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете использовать 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), поэтому фактические данные массива не перемещаются.

Я не знал о np.moveaxis, это звучит очень полезно. Буду иметь в виду, спасибо!

Javier 11.04.2023 19:44

Примечание. Я думаю, что ответ Саймона лучше подходит для этого конкретного вопроса, но я оставляю метод для фактического удаления границ вместо их замены, на случай, если это кому-то понадобится.


Ответ 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)

Кажется, это работает для произвольного размера, хотя он не оптимизирован и, вероятно, будет бороться с большими массивами большого размера.

Другие вопросы по теме