Быстрый способ проверить, находятся ли элементы в одном измерении массива numpy в одном измерении другого массива numpy - PullRequest
0 голосов
/ 18 сентября 2018

Допустим, у нас есть два целых числовых массива A и B размером (N, M).Я хотел бы проверить для каждого я в N, A[i,:] в B[i,:].

Реализация цикла for:

for i in range(N):
    C[i] = np.isin(A[i,:],B[i,:])

Однако это довольно медленно для большого массива,Есть ли более быстрый способ реализовать это?(например, векторизация?)

Спасибо!

Ответы [ 3 ]

0 голосов
/ 18 сентября 2018

Вот один векторизованный подход, основанный на смещении для каждой строки, как обсуждено более подробно в Vectorized searchsorted numpy's solution -

# https://stackoverflow.com/a/40588862/ @Divakar
def searchsorted2d(a,b):
    m,n = a.shape
    max_num = np.maximum(a.max() - a.min(), b.max() - b.min()) + 1
    r = max_num*np.arange(a.shape[0])[:,None]
    p = np.searchsorted( (a+r).ravel(), (b+r).ravel() ).reshape(m,-1)
    return p - n*(np.arange(m)[:,None])

def numpy_isin2D(A,B):
    sB = np.sort(B,axis=1)
    idx = searchsorted2d(sB,A)
    idx[idx==sB.shape[1]] = 0
    return np.take_along_axis(sB, idx, axis=1) == A

Пример выполнения -

In [351]: A
Out[351]: 
array([[5, 0, 3, 3],
       [7, 3, 5, 2],
       [4, 7, 6, 8],
       [8, 1, 6, 7],
       [7, 8, 1, 5]])

In [352]: B
Out[352]: 
array([[8, 4, 3, 0, 3, 5],
       [0, 2, 3, 8, 1, 3],
       [3, 3, 7, 0, 1, 0],
       [4, 7, 3, 2, 7, 2],
       [0, 0, 4, 5, 5, 6]])

In [353]: numpy_isin2D(A,B)
Out[353]: 
array([[ True,  True,  True,  True],
       [False,  True, False,  True],
       [False,  True, False, False],
       [False, False, False,  True],
       [False, False, False,  True]])
0 голосов
/ 18 сентября 2018

Пакет numpy_indexed (отказ от ответственности: я его автор) может быть использован для получения решения, аналогичного Divakars, но с удаленными подробностями низкого уровня:

import numpy_indexed as npi
Ar = np.indices(A.shape)[0]
Br = np.indices(B.shape)[0]
isin = npi.in_((A.flatten(), Ar.flatten()), (B.flatten(), Br.flatten())).reshape(A.shape)

Все функции в пакете numpy_indexed одинаково работают с ndarrays, или, в этом случае, с кортежами ndarrays, что на практике равносильно «заархивированию» ndarrays в кортеже и выполнению этих действий без дополнительных затрат.Таким образом, мы проверяем включение в 1-й набор каждого элемента, заархивированного индексом строки;поэтому совпадения регистрируются только тогда, когда совпадают и индекс строки, и числовое значение.

Решение Divakars, вероятно, имеет преимущество в скорости, но оба решения должны иметь одинаковую сложность по времени.И решение, опубликованное здесь, работает с произвольными dtypes;или даже если токены, которые вы пытаетесь сопоставить, сами являются ndarrays, а не скалярами!

0 голосов
/ 18 сентября 2018

Может быть, что-то вроде этого:

>A = np.zeros((5, 5))
>B = np.ones((5, 5))
>B[2, :] = 0
>print(A)
array([[0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.]])
>print(B)
array([[1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.],
       [0., 0., 0., 0., 0.],
       [1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.]])
>(A == B).all(axis=1)
array([False, False,  True, False, False])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...