为muliple数组实现numpy.in1d的最有效方法

时间:2015-05-06 16:09:18

标签: python arrays sorting numpy indexing

实现一个函数的最佳方法是什么,该函数接受任意数量的1d数组并返回包含匹配值索引(如果有)的元组。

以下是我想要做的一些伪代码:

a = np.array([1, 0, 4, 3, 2])
b = np.array([1, 2, 3, 4, 5])
c = np.array([4, 2])

(ind_a, ind_b, ind_c) = return_equals(a, b, c)
# ind_a = [2, 4]
# ind_b = [1, 3]
# ind_c = [0, 1]

(ind_a, ind_b, ind_c) = return_equals(a, b, c, sorted_by=a)
# ind_a = [2, 4]
# ind_b = [3, 1]
# ind_c = [0, 1]

def return_equals(*args, sorted_by=None):
    ...

4 个答案:

答案 0 :(得分:5)

您可以将numpy.intersect1dreduce一起使用:

def return_equals(*arrays):
    matched = reduce(np.intersect1d, arrays)
    return np.array([np.where(np.in1d(array, matched))[0] for array in arrays])

reduce在这里可能会有点慢,因为我们在这里创建中间NumPy数组(对于大量输入它可能非常慢),如果我们使用Python {{1}我们可以阻止这种情况}及其set方法:

.intersection()

相关GitHub票证:n-array versions of set operations, especially intersect1d

答案 1 :(得分:0)

首先,我会尝试:

Short

如果我添加Long(它只有1个匹配;如果没有匹配则该怎么办?)

然后

def return_equals(*args):
    x=[]
    c=args[-1]
    for a in args:
        x.append(np.nonzero(np.in1d(a,c))[0])
    return x

产生

d=np.array([1,0,4,3,0])

由于输入和返回数组的长度可能不同,因此您无法对问题进行矢量化。也就是说,需要一些特殊的体操来同时在所有输入上执行操作。如果阵列数量与其典型长度相比较小,我不会担心速度。迭代几次并不昂贵。它正在迭代超过100个昂贵的值。

当然,您可以将关键字参数传递给return_equals(a,b,d,c)

目前尚不清楚您要对[array([2, 4], dtype=int32), array([1, 3], dtype=int32), array([2], dtype=int32), array([0, 1], dtype=int32)] 参数做什么。在将数组传递给此函数之前,您是否可以轻松应用于数组?

此迭代的列表理解版本:

in1d

我可以想象将数组连接成一个较长的数组,应用sorted_by,然后将其拆分为子数组。有一个 [np.nonzero(np.in1d(x,c))[0] for x in [a,b,d,c]] ,但它要求您告诉它要在每个子列表中放入多少元素。这意味着,不知何故,确定每个参数有多少匹配。没有循环就这样做可能会很棘手。

这部分(仍然需要打包为函数)是:

in1d

np.splitargs=[a,b,d,c] lens=[len(x) for x in args] abc=np.concatenate(args) C=np.cumsum(lens) I=np.nonzero(np.in1d(abc,c))[0] S=np.split(I,(2,4,5)) [S[0],S[1]-C[0],S[2]-C[1],S[3]-C[2]] I # array([ 2, 4, 6, 8, 12, 15, 16], dtype=int32) C # array([ 5, 10, 15, 17], dtype=int32) 的连续值之间(2,4,5)的元素数,即每个IC匹配的元素数量},...

答案 2 :(得分:0)

在Python中:

def return_equal(*args):
    rtr=[]
    for i, arr in enumerate(args):
        rtr.append([j for j, e in enumerate(arr) if 
                    all(e in a for a in args[0:i]) and 
                    all(e in a for a in args[i+1:])])
    return rtr    

>>> return_equal(a,b,c) 
[[2, 4], [1, 3], [0, 1]]

答案 3 :(得分:0)

此解决方案基本上将所有输入1D数组连接成一个大1D数组,目的是在vectorized manner中执行所需的操作。它使用循环的唯一地方是在开始时获取输入数组的长度,这必须在运行时成本上最小化。

这是功能实现 -

import numpy as np

def return_equals(*argv):
    # Concatenate input arrays into one big array for vectorized processing
    A = np.concatenate((argv[:]))

    # lengths of input arrays
    narr = len(argv)
    lens = np.zeros((1,narr),int).ravel()
    for i in range(narr):
        lens[i] = len(argv[i])  

    N = A.size

    # Start indices of each group of identical elements from different input arrays
    # in a sorted version of the huge concatenated input array
    start_idx = np.where(np.append([True],np.diff(np.sort(A))!=0))[0]

    # Runlengths of islands of identical elements
    runlens = np.diff(np.append(start_idx,N))

    # Starting and all indices of the positions in concatenate array that has 
    # islands of identical elements which are present across all input arrays
    good_start_idx = start_idx[runlens==narr]
    good_all_idx = good_start_idx[:,None] + np.arange(narr)

    # Get offsetted indices and sort them to get the desired output
    idx = np.argsort(A)[good_all_idx] - np.append([0],lens[:-1].cumsum())
    return np.sort(idx.T,1)