Двухъярусный массив фильтров Python по условию

Новичок Python здесь, я прочитал фильтр строк массива NumPy? и документ, но все еще не может понять, как кодировать его на языке Python.

Пример массива у меня есть: (реальные данные 50000 х 10)

a = numpy.asarray([[2,'a'],[3,'b'],[4,'c'],[5,'d']])
filter = ['a','c']

Мне нужно найти все строки в a с a[:, 1] in filter, Ожидаемый результат:

[[2,'a'],[4,'c']]

Мой текущий код такой:

numpy.asarray([x for x in a if x[1] in filter ])

Это работает хорошо, но я где-то читал, что это не эффективно. Какой правильный метод NumPy для этого?

Редактировать:

Спасибо за все правильные ответы! К сожалению, я могу отметить только один принятый ответ. Я удивлен, что numpy.in1d не отображается в поиске Google для numpy filter 2d array,

4 ответа

Решение

Вы можете использовать bool индексный массив, который вы можете создать, используя np.in1d,

Вы можете индексировать np.ndarray вдоль любого axis Вы хотите использовать, например, массив bool s указывает, должен ли элемент быть включен. Поскольку вы хотите индексировать вместе axis=0 Это означает, что вы хотите выбрать из индекса наивысшего, вам нужно иметь 1D np.array длина которого является числом строк. Каждый из его элементов будет указывать, должна ли быть включена строка.

Быстрый способ получить это - использовать np.in1d во втором столбце a, Вы получаете все элементы этого столбца a[:, 1], Теперь у вас есть 1D np.array чьи элементы должны быть проверены по вашему фильтру. Это то что np.in1d для.

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

import numpy as np

a = np.asarray([[2,'a'],[3,'b'],[4,'c'],[5,'d']])
filter = np.asarray(['a','c'])
a[np.in1d(a[:, 1], filter)]

или в более длинной форме:

import numpy as np

a = np.asarray([[2,'a'],[3,'b'],[4,'c'],[5,'d']])
filter = np.asarray(['a','c'])
mask = np.in1d(a[:, 1], filter)
a[mask]

Несколько сложный чистый numpy векторизованное решение:

>>> import numpy
>>> a = numpy.asarray([[2,'a'],[3,'b'],[4,'c'],[5,'d']])
>>> filter = numpy.array(['a','c'])
>>> a[(a[:,1,None] == filter[None,:]).any(axis=1)]
array([['2', 'a'],
       ['4', 'c']], 
      dtype='|S21')

None в индексе создает одноэлементное измерение, поэтому мы можем сравнить столбец a и ряд filter, а затем уменьшить полученный логический массив

>>> a[:,1,None] == filter[None,:]
array([[ True, False],
       [False, False],
       [False,  True],
       [False, False]], dtype=bool)

во втором измерении с any,

Попробуй это:

>>> a[numpy.in1d(a[:,1], filter)]
array([['2', 'a'],
       ['4', 'c']], 
      dtype='|S21')

Также просмотрите http://docs.scipy.org/doc/numpy/reference/generated/numpy.in1d.html

В этом случае, когда len(filter) достаточно меньше, чем a[:,1], np.in1d делает итерационную версию

mask = (a[:,1,None] == filter[None,:]).any(axis=1)
a[mask,:]

Это делает (адаптируя in1d код):

In [1301]: arr1=a[:,1];arr2=np.array(filter)
In [1302]: mask=np.zeros(len(arr1),dtype=np.bool)
In [1303]: for i in arr2:
      ...:     mask |= (arr1==i)
In [1304]: mask
Out[1304]: array([ True, False,  True, False], dtype=bool)

С большим количеством предметов в filter это будет строить свой поиск вокруг unique, concatenate а также argsortищу дубликаты.

Так что это удобство скрывает изрядное количество сложности.

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