2009-10-23 4 views
37

Кто-нибудь когда-нибудь сталкивался с этой проблемой? Скажем, у вас есть два массива, как в следующемNumPy: Сравнение элементов в двух массивах

a = array([1,2,3,4,5,6]) 
b = array([1,4,5]) 

Есть ли способ, чтобы сравнить, какие элементы в существующем в б? Например,

c = a == b # Wishful example here 
print c 
array([1,4,5]) 
# Or even better 
array([True, False, False, True, True, False]) 

Я стараюсь избегать циклов, так как это потребует возраста с миллионами элементов. Есть идеи?

Приветствия

+0

Какие данные у вас есть в массивах? Индексированные уникальные целые числа, например, пример? – u0b34a0f6ae

ответ

47

На самом деле, есть еще более простое решение, чем любой из них:

import numpy as np 

a = array([1,2,3,4,5,6]) 
b = array([1,4,5]) 

c = np.in1d(a,b) 

В результате с тогда:

array([ True, False, False, True, True, False], dtype=bool) 
+6

Есть ли такая «почти равная» версия? Где вы можете указать условие, используемое для проверки равенства? – endolith

-2

Ваш пример предполагает установить, как поведение, уход больше о существовании в массиве, чем иметь правильный элемент в нужном месте. Numpy делает это по-разному с его математическими массивами и матрицами, он расскажет вам только об элементах в точном правильном месте. Можете ли вы сделать эту работу для вас?

>>> import numpy 
>>> a = numpy.array([1,2,3]) 
>>> b = numpy.array([1,3,3]) 
>>> a == b 
array([ True, False, True], dtype=bool) 
+0

Извините, этот пример не работает, если вы попробуете его; кроме того, вам придется сначала отсортировать массивы. – dalloliogm

+0

@ dalloligom: Я скопировал из своего интерактивного сеанса, так что, по крайней мере, он работает точно так же, как для некоторой версии Python и Numpy. – u0b34a0f6ae

+0

нормально, но это не работает, если два массива имеют разную длину; в любом случае вам нужно сначала их отсортировать (попробуйте array ([1,2,3]) == array ([2,3,1]). Он хочет знать, какие элементы массива существуют в другом. – dalloliogm

2

Спасибо за ваш ответ kaizer.se. Это не совсем то, что я искал, но с предложением от друга и того, что вы сказали, я придумал следующее.

import numpy as np 

a = np.array([1,4,5]).astype(np.float32) 
b = np.arange(10).astype(np.float32) 

# Assigning matching values from a in b as np.nan 
b[b.searchsorted(a)] = np.nan 

# Now generating Boolean arrays 
match = np.isnan(b) 
nonmatch = match == False 

Это немного громоздкий процесс, но он бьет писать петли или с помощью переплетения с петлями.

Приветствия

+0

Проблема с этим подходом заключается в том, что он возвращает индексы даже для значений в 'a', которые не существуют в' b' (а также дублирующие индексы в других случаях). Например: 'numpy.searchsorted ([1, 2], [1.2, 1.3 ]) 'возвращает' [1, 1] ', который не подходит для OP. – sirfz

2

Numpy имеет множество функций numpy.setmember1d(), которая работает с отсортированными и uniqued массивов и возвращает именно булево массив, который вы хотите. Если входные массивы не соответствуют критериям, которые вам нужно преобразовать в заданный формат и инвертировать преобразование результата.

import numpy as np 
a = np.array([6,1,2,3,4,5,6]) 
b = np.array([1,4,5]) 

# convert to the uniqued form 
a_set, a_inv = np.unique1d(a, return_inverse=True) 
b_set = np.unique1d(b) 
# calculate matching elements 
matches = np.setmea_set, b_set) 
# invert the transformation 
result = matches[a_inv] 
print(result) 
# [False True False False True True False] 

Edit: К сожалению setmember1d метод в NumPy действительно неэффективно. Выбранный способ поиска и сортировки поиска работает быстрее, но если вы можете назначить напрямую, вы можете также напрямую назначить результат и избежать большого количества ненужного копирования. Также ваш метод будет терпеть неудачу, если b содержит что-либо не в a. Ниже исправляет эти ошибки:

result = np.zeros(a.shape, dtype=np.bool) 
idxs = a.searchsorted(b) 
idxs = idxs[np.where(idxs < a.shape[0])] # Filter out out of range values 
idxs = idxs[np.where(a[idxs] == b)] # Filter out where there isn't an actual match 
result[idxs] = True 
print(result) 

Мои тесты показывают это в 91us против 6.6ms для вашего подхода и 109ms для Numpy setmember1d на 1M элемента а и 100 элемента Ь.

+0

Это приятное решение. Я попробую ваше предложение и то, что я только что написал, чтобы узнать, что более оптимально по скорости. Большое спасибо всем за ваш help! – ebressert

+0

Метод, который я написал, немного быстрее. Для массива элементов 10000 время, затраченное на использование timeit в iPython, составляет примерно 3 мкс. Setmember1d m Этод занял 3 мс. Я думаю, что ваш метод более изящный, но мне нужна скорость. – ebressert

+0

вы забыли закрыть круглую скобку в третьей строке. вы должны исправить это, прежде чем какой-то профессор компьютерных наук замечает это ... – dalloliogm

18

Использование np.intersect1d.

#!/usr/bin/env python 
import numpy as np 
a = np.array([1,2,3,4,5,6]) 
b = np.array([1,4,5]) 
c=np.intersect1d(a,b) 
print(c) 
# [1 4 5] 

Обратите внимание, что np.intersect1d дает неправильный ответ, если б или есть неуникальные элементы. В этом случае используйте np.intersect1d_nu.

Существует также np.setdiff1d, setxor1d, setmember1d и union1d. См. Numpy Example List With Doc

+0

+1: Отлично. Правильная функция для этой задачи. – tom10

0

ebresset, your answer не будет работать, если a не является подмножеством b (а a и b отсортированы). В противном случае searchsorted вернет ложные индексы.Я должен был сделать что-то подобное, и комбинируя, что с вашим кодом:

# Assume a and b are sorted 
idxs = numpy.mod(b.searchsorted(a),len(b)) 
idxs = idxs[b[idxs]==a] 
b[idxs] = numpy.nan 
match = numpy.isnan(b)