Numpy: проверка наличия элемента в многомерном массиве в кортеже
Похоже, я все еще борюсь соператором "in" в numpy . Вот такая ситуация:
>>> a = np.random.randint(1, 10, (2, 2, 3))
>>> a
array([[[9, 8, 8],
[4, 9, 1]],
[[6, 6, 3],
[9, 3, 5]]])
Я хотел бы получить индексы тех триплетов, второй элемент которых находится в
(6, 8). Способ, который я интуитивно попробовал, таков: >>> a[:, :, 1] in (6, 8)
ValueError: The truth value of an array with more than one element...
Моей конечной целью было бы вставить в эти позиции число, предшествующее числу, умноженному на два. используя приведенный выше пример, a должно стать:
array([[[9, 18, 8], #8 @ pos #2 --> replaced by 9 @ pos #1 by 2
[4, 9, 1]],
[[6, 12, 3], #6 @ pos #2 --> replaced by 6 @ pos #1 by 2
[9, 3, 5]]])
Заранее благодарю вас за совет и время!
4 ответов:
import numpy as np a = np.array([[[9, 8, 8], [4, 9, 1]], [[6, 6, 3], [9, 3, 5]]]) ind=(a[:,:,1]<=8) & (a[:,:,1]>=6) a[ind,1]=a[ind,0]*2 print(a)Выходы
[[[ 9 18 8] [ 4 9 1]] [[ 6 12 3] [ 9 3 5]]]
Если вы хотите проверить принадлежность к набору, который не является простым диапазоном, то мне нравится как идея mac использования цикла Python, так и идея bellamyj использования np. in1d. который быстрее зависит от размера
check_tuple:Test.py:
import numpy as np np.random.seed(1) N = 10 a = np.random.randint(1, 1000, (2, 2, 3)) check_tuple = np.random.randint(1, 1000, N) def using_in1d(a): idx = np.in1d(a[:,:,1], check_tuple) idx=idx.reshape(a[:,:,1].shape) a[idx,1] = a[idx,0] * 2 return a def using_in(a): idx = np.zeros(a[:,:,0].shape,dtype=bool) for n in check_tuple: idx |= a[:,:,1]==n a[idx,1] = a[idx,0]*2 return a assert np.allclose(using_in1d(a),using_in(a))Когда N = 10,
using_inнемного быстрее:% python -m timeit -s'import test' 'test.using_in1d(test.a)' 10000 loops, best of 3: 156 usec per loop % python -m timeit -s'import test' 'test.using_in(test.a)' 10000 loops, best of 3: 143 usec per loopКогда N = 100,
using_in1dнамного быстрее:% python -m timeit -s'import test' 'test.using_in1d(test.a)' 10000 loops, best of 3: 171 usec per loop % python -m timeit -s'import test' 'test.using_in(test.a)' 1000 loops, best of 3: 1.15 msec per loop
Вот метод, который будет работать для кортежа произвольной длины. Он использует функцию
numpy.in1d.import numpy as np np.random.seed(1) a = np.random.randint(1, 10, (2, 2, 3)) print(a) check_tuple = (6, 9, 1) bool_array = np.in1d(a[:,:,1], check_tuple) ind = np.where(bool_array)[0] a0 = a[:,:,0].reshape((len(bool_array), )) a1 = a[:,:,1].reshape((len(bool_array), )) a1[ind] = a0[ind] * 2 print(a)И вывод:
[[[6 9 6] [1 1 2]] [[8 7 3] [5 6 3]]] [[[ 6 12 6] [ 1 2 2]] [[ 8 7 3] [ 5 10 3]]]
Есть еще один метод, основанный на использовании таблицы подстановки, который я узнал от одного из разработчиков Cellprofiler. Сначала вам нужно создать таблицу поиска (LUT), которая имеет размер наибольшего числа в вашем массиве. Для каждого возможного значения массива LUT имеет либо истинное, либо ложное значение. Пример:
# create a large volume image with random numbers a = np.random.randint(1, 1000, (50, 1000 , 1000)) labels_to_find=np.unique(np.random.randint(1,1000,500)) # create filter mask LUT def find_mask_LUT(inputarr, obs): keep = np.zeros(np.max(inputarr)+1, bool) keep[np.array(obs)] = True return keep[inputarr] # This will return a mask that is the # same shape as a, with True is a is one of the # labels we look for, False otherwise find_mask_LUT(a, labels_to_find)Это работает очень быстро (намного быстрее, чем np. in1d, и скорость не зависит от количества объектов.)
Вдохновленный Ответ unutbu я нашел это возможное решение:
Однако для предварительного исследования необходимо знать размеры массива.>>> l = (8, 6) >>> idx = np.zeros((2, 2), dtype=bool) >>> for n in l: ... idx |= a[:,:,1] == n >>> idx array([[ True, False], [ True, False]], dtype=bool) >>> a[idx] array([[9, 8, 8], [6, 6, 3]])
Comments