Вопрос индексации Numpy.array - PullRequest
       2

Вопрос индексации Numpy.array

6 голосов
/ 21 октября 2010

Я пытаюсь создать «маску» для numpy.array, указав определенные критерии. Python даже имеет хороший синтаксис для чего-то вроде этого:

>> A = numpy.array([1,2,3,4,5])
>> A > 3
array([False, False, False, True, True])

Но если у меня есть список критериев вместо диапазона:

>> A = numpy.array([1,2,3,4,5])
>> crit = [1,3,5]

Я не могу этого сделать:

>> A in crit

Я должен сделать что-то на основе понимания списка, например:

>> [a in crit for a in A]
array([True, False, True, False, True])

Что правильно.

Теперь проблема в том, что я работаю с большими массивами, а приведенный выше код работает очень медленно. Есть ли более естественный способ выполнить эту операцию, которая могла бы ускорить ее?

РЕДАКТИРОВАТЬ: я смог получить небольшое ускорение, превратив крит в сет.

EDIT2: для тех, кому интересно:

Подход Джуни: 1000 петель, лучшее из 3: 102 мкс на петлю

numpy.in1d: 1000 циклов, лучшее из 3: 1,33 мс на цикл

EDIT3: только что снова протестировано с B = randint (10, размер = 100)

Подход Джуни: 1000 циклов, лучшее из 3: 2,96 мс на цикл

numpy.in1d: 1000 циклов, лучшее из 3: 1,34 мс на цикл

Заключение : Используйте numpy.in1d ​​(), если B не очень маленький.

Ответы [ 3 ]

6 голосов
/ 21 октября 2010

Я думаю, что функция numpy in1d - это то, что вы ищете:

>>> A = numpy.array([1,2,3,4,5])
>>> B = [1,3,5]
>>> numpy.in1d(A,crit)
array([ True, False,  True, False,  True], dtype=bool)

, как указано в строке документации: "in1d(a, b) примерно эквивалентно np.array([item in b for item in a])"

По общему признанию, я не делал никаких тестов скорости, но это похоже на то, что вы ищете.

Еще один более быстрый способ

Вот еще один способ сделать эточто быстрее.Сначала выполните сортировку массива B (содержащего элементы, которые вы хотите найти в A), превратите его в пустой массив, а затем выполните:

B[B.searchsorted(A)] == A

, хотя, если у вас есть элементы в A, которые больше, чемсамое большое в B, вам нужно будет сделать:

inds = B.searchsorted(A)
inds[inds == len(B)] = 0
mask = B[inds] == A

Возможно, оно не будет быстрее для небольших массивов (особенно если B будет маленьким), но вскоре оно определенно будет быстрее.Зачем?Поскольку это алгоритм O (N log M), где N - это количество элементов в A, а M - это количество элементов в M, объединение нескольких отдельных масок - это O (N * M).Я проверил это с N = 10000 и M = 14, и это было уже быстрее.Во всяком случае, просто подумал, что вы хотели бы знать, особенно если вы действительно планируете использовать это на очень больших массивах.

3 голосов
/ 21 октября 2010

Объединить несколько сравнений с "или":

A = randint(10,size=10000)
mask = (A == 1) | (A == 3) | (A == 5)

Или, если у вас есть список B и вы хотите создать маску динамически:

B = [1, 3, 5]
mask = zeros((10000,),dtype=bool)
for t in B: mask = mask | (A == t)
0 голосов
/ 21 октября 2010

Создайте маску и используйте функцию сжатия массива numpy. Это должно быть намного быстрее. Если у вас есть сложные критерии, не забудьте построить их на основе математики массивов.

a = numpy.array([3,1,2,4,5])
mask = a > 3
b = a.compress(mask)

или

a = numpy.random.random_integers(1,5,100000)
c=a.compress((a<=4)*(a>=2)) ## numbers between n<=4 and n>=2
d=a.compress(~((a<=4)*(a>=2))) ## numbers either n>4 or n<2

Хорошо, если вы хотите маску, которая имеет все a в [1,3,5], вы можете сделать что-то вроде

a = numpy.random.random_integers(1,5,100000)
mask=(a==1)+(a==3)+(a==5)

или

a = numpy.random.random_integers(1,5,100000)
mask = numpy.zeros(len(a), dtype=bool)
for num in [1,3,5]:
    mask += (a==num)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...