Моя проблема

Предположим, у меня есть

a = np.array([ np.array([1,2]), np.array([3,4]), np.array([5,6]), np.array([7,8]), np.array([9,10])])
b = np.array([ np.array([5,6]), np.array([1,2]), np.array([3,192])])

Это два массива разных размеров, содержащие другие массивы (внутренние массивы имеют одинаковые размеры!)

Я хочу посчитать, сколько элементов b (то есть внутренних массивов) также есть в a. Обратите внимание, что я не рассматриваю их позицию!

Как я могу это сделать?

Моя попытка

count = 0
for bitem in b:
     for aitem in a:
         if aitem==bitem:
               count+=1

Есть ли способ лучше? Особенно в одной строке, может быть, с некоторым пониманием ..

5
Euler_Salter 29 Авг 2017 в 13:00

4 ответа

Лучший ответ

пакет numpy_indexed содержит эффективные (как правило, nlogn) и векторизованные решения этих типов проблем:

import numpy_indexed as npi
count = len(npi.intersection(a, b))

Обратите внимание, что это немного отличается от вашего двойного цикла, исключая, например, повторяющиеся записи в a и b. Если вы хотите сохранить дубликаты в b, это будет работать:

count = npi.in_(b, a).sum()

Дубликаты записей в a также могут обрабатываться с помощью npi.count (a) и с учетом этого; но в любом случае, я просто бродил в целях иллюстрации, так как я представляю, что различие, вероятно, не имеет значения для вас.

2
Eelco Hoogendoorn 29 Авг 2017 в 21:25

Вы можете делать то, что вы хотите в одном вкладыше, следующим образом:

count = sum([np.array_equal(x,y) for x,y in product(a,b)])

Объяснение

Вот объяснение того, что происходит:

  1. Выполните итерацию по двум массивам, используя itertools.product, который создаст итератор над декартово произведение двух массивов.
  2. Сравните каждые два массива в кортеже (x, y), полученном на шаге 1., используя np.array_equal
  3. Истина равна 1 при использовании суммы в списке

Полный пример:

Окончательный код выглядит так:

import numpy as np 
from itertools import product 
a = np.array([ np.array([1,2]), np.array([3,4]), np.array([5,6]), np.array([7,8]), np.array([9,10])])
b = np.array([ np.array([5,6]), np.array([1,2]), np.array([3,192])])
count = sum([np.array_equal(x,y) for x,y in product(a,b)])
# output: 2
2
Mohamed Ali JAMAOUI 30 Авг 2017 в 07:31

Вы можете преобразовать строки в dtype = np.void, а затем использовать np.in1d как в полученных 1d массивах

def void_arr(a):
    return np.ascontiguousarray(a).view(np.dtype((np.void, a.dtype.itemsize * a.shape[1]))) 

b[np.in1d(void_arr(b), void_arr(a))]

array([[5, 6],
       [1, 2]])

Если вы просто хотите количество пересечений, это

np.in1d(void_arr(b), void_arr(a)).sum()

2

Примечание. если в b или a есть повторяющиеся элементы, то np.in1d(void_arr(b), void_arr(a)).sum(), скорее всего, не будет равен np.in1d(void_arr(a), void_arr(b)).sum(). Я изменил порядок в своем исходном ответе, чтобы соответствовать вашему вопросу (т. Е. Сколько элементов b находится в a?)

Дополнительную информацию смотрите в третьем ответе здесь.

1
Daniel F 29 Авг 2017 в 11:00

Вот простой способ сделать это:

a = np.array([ np.array([1,2]), np.array([3,4]), np.array([5,6]), np.array([7,8]), np.array([9,10])])
b = np.array([ np.array([5,6]), np.array([1,2]), np.array([3,192])])

count = np.count_nonzero(
    np.any(np.all(a[:, np.newaxis, :] == b[np.newaxis, :, :], axis=-1), axis=0))

print(count)
>>> 2
2
jdehesa 29 Авг 2017 в 11:30