Замена 2D подмассива в 3D массиве, если условие выполнено - PullRequest
0 голосов
/ 28 апреля 2018

У меня есть матрица, которая выглядит так:

a = np.random.rand(3, 3, 3)

[[[0.04331462, 0.30333583, 0.37462236],
  [0.30225757, 0.35859228, 0.57845153],
  [0.49995805, 0.3539933,  0.11172398]],

 [[0.28983508, 0.31122743, 0.67818926],
  [0.42720309, 0.24416101, 0.5469823 ],
  [0.22894097, 0.76159389, 0.80416832]],

 [[0.25661154, 0.64389696, 0.37555374],
  [0.87871659, 0.27806621, 0.3486518 ],
  [0.26388296, 0.8993144,  0.7857116 ]]]

Я хочу проверить каждый блок на значение меньше 0,2. Если значение меньше 0,2, тогда весь блок равен 0,2. В этом случае:

[[[0.2 0.2 0.2]
  [0.2 0.2 0.2]
  [0.2 0.2 0.2]]

[[0.28983508 0.31122743 0.67818926]
 [0.42720309 0.24416101 0.5469823 ]
 [0.22894097 0.76159389 0.80416832]]

[[0.25661154 0.64389696 0.37555374]
 [0.87871659 0.27806621 0.3486518 ]
 [0.26388296 0.8993144  0.7857116 ]]]

Ответы [ 4 ]

0 голосов
/ 28 апреля 2018

Вот векторизованный способ получить то, что вы хотите.
Взяв a из вашего примера:

a[(a < 0.2).any(axis=1).any(axis=1)] = 0.2
print(a)

дает:

array([[[ 0.2       ,  0.2       ,  0.2       ],
        [ 0.2       ,  0.2       ,  0.2       ],
        [ 0.2       ,  0.2       ,  0.2       ]],

       [[ 0.28983508,  0.31122743,  0.67818926],
        [ 0.42720309,  0.24416101,  0.5469823 ],
        [ 0.22894097,  0.76159389,  0.80416832]],

       [[ 0.25661154,  0.64389696,  0.37555374],
        [ 0.87871659,  0.27806621,  0.3486518 ],
        [ 0.26388296,  0.8993144 ,  0.7857116 ]]])

Объяснение:

Возьмем другой пример, где каждый шаг будет более понятным:

a = np.array([[[0.51442898, 0.90447442, 0.45082496],
               [0.59301203, 0.30025497, 0.43517362],
               [0.28300437, 0.64143037, 0.73974422]],
              [[0.228676  , 0.59093859, 0.14441217],
               [0.37169639, 0.57230533, 0.81976775],
               [0.95988687, 0.43372407, 0.77616701]],
              [[0.03098771, 0.80023031, 0.89061113],
               [0.86998351, 0.39619143, 0.16036088],       
               [0.24938437, 0.79131954, 0.38140462]]])

Посмотрим, какие элементы меньше 0,2:

print(a < 0.2)

дает:

array([[[False, False, False],
        [False, False, False],
        [False, False, False]],

       [[False, False,  True],
        [False, False, False],
        [False, False, False]],

       [[ True, False, False],
        [False, False,  True],
        [False, False, False]]])

Отсюда мы хотели бы получить индексы тех двумерных массивов, которые имеют хотя бы один элемент True: [False, True, True]. Для этого нам требуется np.any. Обратите внимание, что здесь я буду использовать цепочку методов np.ndarray.any вместо вызовов вложенных функций np.any. 1

Теперь просто использование (a < 0.2).any() даст только True, потому что по умолчанию он выполняет логическое ИЛИ для всех измерений. Мы должны указать axis параметр. В нашем случае все будет в порядке с axis=1 или axis=2. 2

print((a < 0.2).any(axis=1))

дает 3

array([[False, False, False],
       [False, False,  True],
       [ True, False,  True]])

Отсюда мы получаем желаемые логические индексы, применяя еще один .any() вдоль строк:

print((a < 0.2).any(axis=1).any(axis=1))

дает:

array([False,  True,  True])

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

a[(a < 0.2).any(axis=1).any(axis=1)] = 0.2
print(a)

дает:

array([[[0.51442898, 0.90447442, 0.45082496],
        [0.59301203, 0.30025497, 0.43517362],
        [0.28300437, 0.64143037, 0.73974422]],

       [[0.2       , 0.2       , 0.2       ],
        [0.2       , 0.2       , 0.2       ],
        [0.2       , 0.2       , 0.2       ]],

       [[0.2       , 0.2       , 0.2       ],
        [0.2       , 0.2       , 0.2       ],
        [0.2       , 0.2       , 0.2       ]]])

1 Просто сравните цепочку:

a[(a < 0.2).any(axis=1).any(axis=1)] = 0.2

с вложенностью:

a[np.any(np.any(a < 0.2, axis=1), axis=1)] = 0.2

Я думаю, что последнее более запутанно.

2 Поначалу мне было трудно это понять. Что мне помогло, так это нарисовать изображение куба 3x3x3, распечатать результаты для разных осей и проверить, какая ось соответствует каким направлениям. Кроме того, здесь приведено объяснение использования оси с np.sum в трехмерном случае: Ось в многомерном массиве Numpy.

3 Можно ожидать, что вы получите [False, True, True] сразу, но это не так. Для объяснения см. Это: Небольшое уточнение необходимо для numpy.any для матриц

0 голосов
/ 28 апреля 2018

Вы можете проверить, имеет ли блок значения меньше 0,2, а затем установить желаемое значение на весь блок:

a = np.random.rand(3, 3, 3)

for i in range(0, len(a)):
    if len(a[i][a[i] < 0.2]) > 0:
        a[i] = 0.2
0 голосов
/ 28 апреля 2018
for i, block in enumerate(a):
    if (block < 0.2).flatten().any():
        a[i] = np.ones(np.shape(block)) * 0.2

print(a)

array([[[ 0.2       ,  0.2       ,  0.2       ],
        [ 0.2       ,  0.2       ,  0.2       ],
        [ 0.2       ,  0.2       ,  0.2       ]],

       [[ 0.28983508,  0.31122743,  0.67818926],
        [ 0.42720309,  0.24416101,  0.5469823 ],
        [ 0.22894097,  0.76159389,  0.80416832]],

       [[ 0.25661154,  0.64389696,  0.37555374],
        [ 0.87871659,  0.27806621,  0.3486518 ],
        [ 0.26388296,  0.8993144 ,  0.7857116 ]]])
0 голосов
/ 28 апреля 2018

Поскольку у вас есть три слоя к вашей матрице, попробуйте это (с вашей матрицей a):

for x in a:
    for y in x:
        for z in y:
            if z < 0.2:
                z=0.2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...