Двухъярусный массив фильтров 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
ищу дубликаты.
Так что это удобство скрывает изрядное количество сложности.