在ndarray中统计独特的元素

时间:2015-03-01 01:20:21

标签: python arrays numpy

this问题的扩展。除了行列式的独特元素之外,我想要一个类似形状的数组,它给出了唯一值的计数。例如,如果初始数组如下所示:

a = np.array([[1,  2, 2, 3,  4, 5],
              [1,  2, 3, 3,  4, 5],
              [1,  2, 3, 4,  4, 5],
              [1,  2, 3, 4,  5, 5],
              [1,  2, 3, 4,  5, 6]])

我想将此作为函数的输出:

np.array([[1,  2, 0, 1,  1, 1],
          [1,  1, 2, 0,  1, 1],
          [1,  1, 1, 2,  0, 1],
          [1,  1, 1, 1,  2, 0],
          [1,  1, 1, 1,  1, 1]])

在numpy v.1.9中,似乎有一个额外的参数return_counts可以返回一个扁平数组中的计数。是否有某种方法可以将这些值重新构造到原始数组维度中,并使用零重复值?

2 个答案:

答案 0 :(得分:1)

这个答案背后的想法与used here非常相似。我正在为每一行添加一个唯一的虚数。因此,来自不同行的两个数字不能相等。因此,您只需拨打np.unique一次,就可以在每个行每行中找到所有唯一值

ind为您提供每个唯一值首次出现的位置时,返回索引return_index=True

cnt为您提供计数时,计数return_counts=True会返回。

np.put(b, ind, cnt)将计数放在每个唯一值的第一个出现位置。

这里使用的技巧的一个明显限制是原始数组必须具有int或float dtype。它不能以复杂的dtype开头,因为每行乘以一个唯一的虚数可能会产生不同行的重复对。


import numpy as np

a = np.array([[1,  2, 2, 3,  4, 5],
              [1,  2, 3, 3,  4, 5],
              [1,  2, 3, 4,  4, 5],
              [1,  2, 3, 4,  5, 5],
              [1,  2, 3, 4,  5, 6]])

def count_unique_by_row(a):
    weight = 1j*np.linspace(0, a.shape[1], a.shape[0], endpoint=False)
    b = a + weight[:, np.newaxis]
    u, ind, cnt = np.unique(b, return_index=True, return_counts=True)
    b = np.zeros_like(a)
    np.put(b, ind, cnt)
    return b

产量

In [79]: count_unique_by_row(a)
Out[79]: 
array([[1, 2, 0, 1, 1, 1],
       [1, 1, 2, 0, 1, 1],
       [1, 1, 1, 2, 0, 1],
       [1, 1, 1, 1, 2, 0],
       [1, 1, 1, 1, 1, 1]])

答案 1 :(得分:0)

此方法通过对每一行进行排序并获取连续的相等值的长度来与每行np.unique相同。这具有O(NMlog(M))的复杂度,优于在整个阵列上唯一运行,因为它具有O(NM(log(NM))

def row_unique_count(a):                                    
     args = np.argsort(a)
     unique = a[np.indices(a.shape)[0], args]
     changes = np.pad(unique[:, 1:] != unique[:, :-1], ((0, 0), (1, 0)), mode="constant", constant_values=1)
     idxs = np.nonzero(changes)
     tmp = np.hstack((idxs[-1], 0))
     counts = np.where(tmp[1:], np.diff(tmp), a.shape[-1]-tmp[:-1])
     count_array = np.zeros(a.shape, dtype="int")
     count_array[(idxs[0], args[idxs])] = counts
     return count_array

运行时间:

In [162]: b = np.random.random(size=100000).reshape((100, 1000))

In [163]: %timeit row_unique_count(b)
100 loops, best of 3: 10.4 ms per loop

In [164]: %timeit count_unique_by_row(b)
100 loops, best of 3: 19.4 ms per loop

In [165]: assert np.all(row_unique_count(b) == count_unique_by_row(b))