NumPy: сравнение элементов в двух массивах
Кто-нибудь когда-нибудь сталкивался с этой проблемой? Скажем, у вас есть два массива, например, следующие
a = array([1,2,3,4,5,6])
b = array([1,4,5])
Есть ли способ сравнить, какие элементы существуют в b? Например,
c = a == b # Wishful example here
print c
array([1,4,5])
# Or even better
array([True, False, False, True, True, False])
Я пытаюсь избежать циклов, так как потребуется миллионы элементов. Есть идеи?
Приветствия
Ответы
Ответ 1
На самом деле существует еще более простое решение, чем любое из них:
import numpy as np
a = array([1,2,3,4,5,6])
b = array([1,4,5])
c = np.in1d(a,b)
В результате c будет:
array([ True, False, False, True, True, False], dtype=bool)
Ответ 2
Используйте 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 дает неправильный ответ, если a или b имеют неединичные элементы. В этом случае используйте
np.intersect1d_nu.
Существует также np.setdiff1d, setxor1d, setmember1d и union1d. Видеть
Список примеров Numpy с Doc
Ответ 3
Спасибо за ваш ответ 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
Это немного громоздкий процесс, но он превосходит пишущие петли или использует переплетение с петлями.
Приветствия
Ответ 4
У Numpy есть функция set numpy.setmember1d(), которая работает с отсортированными и уникальными массивами и возвращает именно тот булевой массив, который вы хотите. Если входные массивы не соответствуют критериям, которые вам нужно будет преобразовать в заданный формат и инвертировать преобразование результата.
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]
Изменить:
К сожалению, метод 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,6 мс для вашего подхода и 109 мс для numpy setmember1d на элементе 1M a и 100 элементах b.
Ответ 5
ebresset, ваш ответ не будет работать, если 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)
Ответ 6
В вашем примере подразумевается поведение, подобное положению, которое больше заботится о существовании в массиве, чем о правильном элементе в нужном месте. Numpy делает это по-разному с его математическими массивами и матрицами, он расскажет вам только об элементах в точном правильном месте. Можете ли вы сделать эту работу для вас?
>>> import numpy
>>> a = numpy.array([1,2,3])
>>> b = numpy.array([1,3,3])
>>> a == b
array([ True, False, True], dtype=bool)