获取前n个唯一值的索引

时间:2019-03-21 01:44:58

标签: python numpy set

我有两个数组ab,我想为它们找到第一个 n 唯一索引(在a和{{ 1}})项。最好用一个例子来解释:

b

对于n = 1,我期望结果为# 0 1 2 3 4 5 6 7 8 9 10 11 12 a = np.asarray([1, 1, 2, 2, 3, 3, 3, 4, 5, 5, 6, 6, 6]) b = np.asarray([0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 1, 1, 1]) (列表不包含index = 1,因为它已经由index = 0([0, 2, 3, 4, 5, 7, 8, 10])给出,而不是index = 6,因为那是已经由结果列表中的index = 4给出,但不包括index = 9,因为index = 8是等效的。)

对于n = 2,结果应为(a[0], b[0]) == (a[1], b[1])(结果中允许在[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]a上出现2个唯一的出现)。

我不知道如何用numpy来表达这一点……感谢您的帮助。

4 个答案:

答案 0 :(得分:3)

检查以下内容,我正在使用lexsort通过两个数组获取排序顺序,然后使用diffflatnonzero查找需要添加split点的组< / p>

ind = np.lexsort((a, b))

v=np.column_stack([a,b])

sid=np.flatnonzero(np.any(np.diff(v[ind,:].T)>0,0))+1

yourlist=np.split(np.arange(len(a))[ind], sid)

n=1
np.concatenate([x[:n]for x in yourlist])
Out[347]: array([ 0,  3,  4,  7,  8,  2, 10,  5])

答案 1 :(得分:2)

这不是100%NumPy解决方案。最后一步使用列表理解。我不确定100%NumPy解决方案是否可行。但是:

将数组合并为二维数组:

ab2d = np.stack([a, b]).T

查找唯一值:

uniq = np.unique(ab2d, axis=0)

对于每个唯一值,请在2d数组中找到其最小的索引N

N = 2
np.concatenate([np.argwhere((pair == ab2d).all(axis=1))[:N, 0]
                for pair in uniq])
#array([ 0,  1,  3,  2,  4,  6,  5,  7,  8,  9, 10, 11])

答案 2 :(得分:1)

方法1::如果可以使用pandas,则非常简单明了-

In [41]: import pandas as pd

In [42]: df = pd.DataFrame({'a':a,'b':b})

In [43]: [np.flatnonzero(df.groupby(['a','b']).cumcount()<n) for n in [1,2]]
Out[43]: 
[array([ 0,  2,  3,  4,  5,  7,  8, 10]),
 array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])]

方法2:对于具有ints且注重性能的输入数组,我们可以使用 more-NumPy 版本,如下所示-

# https://stackoverflow.com/a/43211485/ @Divakar
def array_cumcount(a):
    idx = np.flatnonzero(a[1:] != a[:-1])+1
    shift_arr = np.ones(a.size,dtype=int)
    shift_arr[0] = 0

    if len(idx)>=1:
        shift_arr[idx[0]] = -idx[0]+1
        shift_arr[idx[1:]] = -idx[1:] + idx[:-1] + 1
    return shift_arr.cumsum()

ab = a*(b.max()+1) + b
sidx = ab.argsort()
ab_s = ab[sidx]
cumcounts = array_cumcount(ab_s)[sidx]
out = [np.flatnonzero(cumcounts<n) for n in [1,2]]

答案 3 :(得分:1)

@Divakar的第二种方法似乎最快。

@DYZ              1000 loops, best of 3: 1.02 ms per loop
@Wen-Ben          1000 loops, best of 3: 234 µs per loop
@Divakar(pandas)   100 loops, best of 3: 1.9 ms per loop
@Divakar(numpy)  10000 loops, best of 3: 58.5 µs per loop

经过测试

a = np.random.randint(10, size=1000, dtype=int)
b = np.random.randint(5, size=1000, dtype=int)
n = 5

,但结论也适用于较小的数组大小和 n 值。粗略地看@DYZ的方法表明np.unique相对较慢,@ ​​Wen-Ben的np.lexsort也相对较慢(列表理解对运行时的贡献不大)。