выполнение операции над выбранными индексами массива numpy на основе значений в другом массиве

#python #arrays #numpy

#питон #массивы #тупой

Вопрос:

У меня есть массив A. У меня есть еще один массив, который я называю switch. Переключатель массива — это массив логических значений (и np.nan, которые соответствуют расположению массивов np.nan 3 x 3 в A), который определяет, какой массив 3 x 3 в A будет выбран для операции.

Пример:

 switch = np.array([ True, False, False, False, np.nan])

a = np.array([[[ 0.,  0.,  0.],
        [ 9.,  0.,  0.],
        [ 3., 15.,  0.]],

       [[ 0.,  0.,  0.],
        [ 9.,  0.,  0.],
        [ 3., 15.,  0.]],

       [[ 0., 27.,  0.],
        [ 0.,  0.,  0.],
        [12., 18.,  0.]],

       [[ 0.,  0.,  6.],
        [12.,  0., 27.],
        [ 0.,  0.,  0.]],

       [[ np.nan, np.nan, np.nan],
        [np.nan, np.nan, np.nan],
        [ np.nan, np.nan, np.nan]]])
 

Окончательный выбранный массив, основанный на приведенном выше примере, должен быть:

 np.array([[[ 0.,  0.,  0.],
            [ 9.,  0.,  0.],
            [ 3., 15.,  0.]],

       [[ np.nan, np.nan, np.nan],
        [np.nan, np.nan, np.nan],
        [ np.nan, np.nan, np.nan]],

       [[ np.nan, np.nan, np.nan],
        [np.nan, np.nan, np.nan],
        [ np.nan, np.nan, np.nan]],

       [[ np.nan, np.nan, np.nan],
        [np.nan, np.nan, np.nan],
        [ np.nan, np.nan, np.nan]],

       [[ np.nan, np.nan, np.nan],
        [np.nan, np.nan, np.nan],
        [ np.nan, np.nan, np.nan]]])
 

Я могу сделать это, используя цикл for и выполняя итерацию по каждому массиву 3 x 3 в A с использованием управляющих операторов if / else, но мне интересно, есть ли способ сделать это, используя встроенную функциональность в numpy. Циклы For и операторы if /else, вероятно, намного медленнее, чем манипулирование массивом. Я повозился, но до сих пор не смог найти оптимального решения numpy.

Я могу реструктурировать переключатель массива, но массив A я не могу изменить структуру / форму.

Комментарии:

1. Уместно: thedailywtf.com/articles/What_Is_Truth_0x3f_

2. Что вы на самом деле пробовали? Numpy поддерживает прямое логическое индексирование

Ответ №1:

Вы можете использовать np.where :

 out = np.where(switch[:,None,None], a, np.nan)
 

Или используйте маскировку:

 out = a.copy()
out[switch!=True] = np.nan
 

Выходной сигнал:

 array([[[ 0.,  0.,  0.],
        [ 9.,  0.,  0.],
        [ 3., 15.,  0.]],

       [[nan, nan, nan],
        [nan, nan, nan],
        [nan, nan, nan]],

       [[nan, nan, nan],
        [nan, nan, nan],
        [nan, nan, nan]],

       [[nan, nan, nan],
        [nan, nan, nan],
        [nan, nan, nan]],

       [[nan, nan, nan],
        [nan, nan, nan],
        [nan, nan, nan]]])
 

Комментарии:

1. Первый метод не работает, но второй метод работает. Есть мысли, почему первое не работает? Я знаю, что nan не является правильной маской bool, но именно так поступают мои данные.

2. Это работает в моей системе с numpy 1.19.2. Возможно, явно использовать switch==True вместо switch helps.

Ответ №2:

Это было бы намного проще, если бы вы использовали правильную логическую маску. Numpy допускает логическую индексацию, но помещение an nan в массив превращает его в a float .

Для этого конкретного примера не имеет значения, какое значение принимают NAN, поэтому вы можете сделать

 switch = switch.astype(bool)
result = np.full_like(a, np.nan)
result[switch] = a[switch]