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
可以返回一个扁平数组中的计数。是否有某种方法可以将这些值重新构造到原始数组维度中,并使用零重复值?
答案 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))