如何按出现频率对唯一的np数组元素进行排序?

3
我想实现以下代码:
a = [1, 1, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5]
sorted(a,key=a.count,reverse=True)
>>> [5, 5, 5, 5, 3, 3, 3, 4, 4, 4, 1, 1, 2]

a 是一个 np.array 的情况下

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

如何操作?np.array 有一个 np.unique() 函数,可以计算每个元素的出现次数,但我不知道如何在这里使用它。

在你的例子中,数字3和4都出现了三次。输出结果中,数字3出现在数字4之前是否很重要?也就是说,在平局的情况下必须满足特殊约束条件吗? - Warren Weckesser
你的实际数据是否只包含像你的示例中那样相对较小的整数? - Warren Weckesser
你尝试过这些解决方案中的任何一个吗? - Divakar
3个回答

2
你可以使用 np.unique 函数,并使用其可选参数 return_countsreturn_inverse。最初的回答。
u, ids, c = np.unique(a, return_counts=True, return_inverse=True)
out = a[c[ids].argsort()[::-1]]

"最初的回答" - 样例运行:
In [90]: a = np.array([1, 1, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5])

In [91]: u, ids, c = np.unique(a, return_counts=True, return_inverse=1)

In [92]: a[c[ids].argsort()[::-1]]
Out[92]: array([5, 5, 5, 5, 4, 4, 4, 3, 3, 3, 1, 1, 2])

1
你正在寻找return_counts,可以将其与argsort+ repeat结合使用。这将不能保证出现相同次数的元素的顺序(注意43之前,计数相同,但不是“稳定”的)。
u, c = np.unique(a, return_counts=True)
i = np.argsort(c)[::-1]
np.repeat(u[i], c[i])

array([5, 5, 5, 5, 4, 4, 4, 3, 3, 3, 1, 1, 2])

1
为了完全模拟sorted/list的行为,可以使用Divakar的解决方案并进行小修改:
al = [1,2,3,2,1,3,2]
aa = np.array(al)

sorted(al, key=al.count, reverse=True)
# [2, 2, 2, 1, 3, 1, 3]

u, ids, c = np.unique(aa, return_counts=True, return_inverse=True)
aa[(-c[ids]).argsort(kind="stable")]
# array([2, 2, 2, 1, 3, 1, 3])

如果aa很大,
from scipy import sparse
sparse.csc_matrix((aa, (c.max()-c[ids]), np.arange(len(ids)+1))).tocsr().data
# array([2, 2, 2, 1, 3, 1, 3], dtype=int64)

可能会稍微快一些。但是,因为在两种情况下我们都首先调用了昂贵的 unique 函数,所以速度提升不会很大,除非数据是较小的整数,在这种情况下,更快的替代方法(@WarrenWeckesser 在评论中提到的)可用,包括我们刚刚使用的稀疏矩阵技巧;例如,请参见 Most efficient way to sort an array into bins specified by an index array?

aaa = np.tile(aa,10000)
timeit(lambda:aaa[(-c[ids]).argsort(kind="stable")], number=10)
# 0.040545254945755005
timeit(lambda:sparse.csc_matrix((aaa, (c.max()-c[ids]), np.arange(len(ids)+1))).tocsr().data, number=10)
# 0.0118721229955554

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接