【问题标题】:Find indices of common values in two arrays在两个数组中查找公共值的索引
【发布时间】:2015-12-15 16:29:17
【问题描述】:

我使用的是 Python 2.7。 我有两个数组,A 和 B。 要查找 B 中存在的 A 中元素的索引,我可以这样做

A_inds = np.in1d(A,B)

我还想获取 B 中存在于 A 中的元素的索引,即我使用上述代码找到的相同重叠元素在 B 中的索引。

目前我再次运行同一行如下:

B_inds = np.in1d(B,A)

但是这个额外的计算似乎应该是不必要的。有没有一种计算效率更高的方法来同时获得A_indsB_inds

我愿意使用列表或数组方法。

【问题讨论】:

  • 输入数组的大小是多少?它们是一维的吗?
  • 大。 10^6 或 10^7 的数量级。
  • 这些数组有独特的元素吗?他们排序了吗?
  • 不幸的是,没有。有许多重复的元素——大约是数组的 5-10%。是的,它们是一维的。
  • 元素没有严格排序。事实上,它们是元组。也许我应该早点提到这一点。

标签: python arrays performance numpy indices


【解决方案1】:

np.uniquenp.searchsorted 可以一起使用来解决它-

def unq_searchsorted(A,B):

    # Get unique elements of A and B and the indices based on the uniqueness
    unqA,idx1 = np.unique(A,return_inverse=True)
    unqB,idx2 = np.unique(B,return_inverse=True)

    # Create mask equivalent to np.in1d(A,B) and np.in1d(B,A) for unique elements
    mask1 = (np.searchsorted(unqB,unqA,'right') - np.searchsorted(unqB,unqA,'left'))==1
    mask2 = (np.searchsorted(unqA,unqB,'right') - np.searchsorted(unqA,unqB,'left'))==1

    # Map back to all non-unique indices to get equivalent of np.in1d(A,B), 
    # np.in1d(B,A) results for non-unique elements
    return mask1[idx1],mask2[idx2]

运行时测试和验证结果 -

In [233]: def org_app(A,B):
     ...:     return np.in1d(A,B), np.in1d(B,A)
     ...: 

In [234]: A = np.random.randint(0,10000,(10000))
     ...: B = np.random.randint(0,10000,(10000))
     ...: 

In [235]: np.allclose(org_app(A,B)[0],unq_searchsorted(A,B)[0])
Out[235]: True

In [236]: np.allclose(org_app(A,B)[1],unq_searchsorted(A,B)[1])
Out[236]: True

In [237]: %timeit org_app(A,B)
100 loops, best of 3: 7.69 ms per loop

In [238]: %timeit unq_searchsorted(A,B)
100 loops, best of 3: 5.56 ms per loop

如果两个输入数组已经是sortedunique,性能提升将是巨大的。因此,求解函数将简化为 -

def unq_searchsorted_v1(A,B):
    out1 = (np.searchsorted(B,A,'right') - np.searchsorted(B,A,'left'))==1
    out2 = (np.searchsorted(A,B,'right') - np.searchsorted(A,B,'left'))==1  
    return out1,out2

后续运行时测试 -

In [275]: A = np.random.randint(0,100000,(20000))
     ...: B = np.random.randint(0,100000,(20000))
     ...: A = np.unique(A)
     ...: B = np.unique(B)
     ...: 

In [276]: np.allclose(org_app(A,B)[0],unq_searchsorted_v1(A,B)[0])
Out[276]: True

In [277]: np.allclose(org_app(A,B)[1],unq_searchsorted_v1(A,B)[1])
Out[277]: True

In [278]: %timeit org_app(A,B)
100 loops, best of 3: 8.83 ms per loop

In [279]: %timeit unq_searchsorted_v1(A,B)
100 loops, best of 3: 4.94 ms per loop

【讨论】:

  • 可以扩展为 3 个数组吗? (或 n 个数组,甚至?)
  • @hm8 我认为一个新问题会很合适,因为它看起来不像是一个简单的扩展。
【解决方案2】:

一个简单的多处理实现会让你更快一点:

import time
import numpy as np

from multiprocessing import Process, Queue

a = np.random.randint(0, 20, 1000000)
b = np.random.randint(0, 20, 1000000)

def original(a, b, q):
    q.put( np.in1d(a, b) )

if __name__ == '__main__':
    t0 = time.time()
    q = Queue()
    q2 = Queue()
    p = Process(target=original, args=(a, b, q,))
    p2 = Process(target=original, args=(b, a, q2))
    p.start()
    p2.start()
    res = q.get()
    res2 = q2.get()

    print time.time() - t0

>>> 0.21398806572 

Divakar 的 unq_searchsorted(A,B) 方法在我的机器上花费了 0.271834135056 秒。

【讨论】:

  • 谢谢你 - 它肯定会有用。目前,虽然我正在寻找单核上最快的方法,因为稍后我将把整个代码分发到多个核上。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-05
  • 2017-01-22
  • 2012-09-12
  • 2011-07-15
  • 1970-01-01
相关资源
最近更新 更多