在一个二维数组中有效地计算每个数字的重复次数

4
我需要在多个一维数组中找到重复数字及其重复次数。对于一维数组,可以使用np.unique函数实现,但似乎并不适用于二维数组。我已经搜索了类似的答案,但我需要更详细的报告(包括所有数字出现的次数和位置索引)。 numpy中的bincount能用于二维数组吗? 这个回答不太符合我的要求,我希望得到一个包含更多数据信息的映射,比如最多出现的数字等。我不喜欢循环嵌套,虽然这可能不太恰当,但我会尝试寻找不使用循环的方法,因为我对速度有非常苛刻的要求。
例如:
a = np.array([[1,2,2,2,3],
              [0,1,1,1,2],
              [0,0,0,1,0]])

# The number of occurrences for each number
# int  count
# 0.     0
# 1.     1
# 2.     3
# 3.     1

#need the output:
#Index = the number of statistics, the number of repetitions
[[0 1 3 1]  
 [1 3 1 0]
 [4 1 0 0]]

因为这是循环的一部分,所以你需要一种有效的方式来矢量化以一次完成更多的统计行,并尝试避免再次循环。
我使用了数据包聚合来计算结果。该函数通过构造区分行的key1,数据本身作为key2,和一个二维数组的所有1来实现。虽然能够输出,但我认为这只是临时措施。需要找到正确的方法。
from numpy_indexed import group_by

def unique2d(x):
    x = x.astype(int); mx = np.nanmax(x)+1

    ltbe = np.tile(np.arange(x.shape[0])[:,None],(1,x.shape[1]))

    vtbe = np.zeros(x.shape).astype(int) + 1

    groups = npi.group_by((ltbe.ravel(),x.ravel().astype(int)))
    unique, median = groups.sum(vtbe.ravel())

    ctbe = np.zeros(x.shape[0]*mx.astype(int)).astype(int)
    ctbe[(unique[0] * mx + unique[1]).astype(int)] = median
    ctbe.shape=(x.shape[0],mx)

    return ctbe

unique2d(a)

>array([[0, 1, 3, 1],
        [1, 3, 1, 0],
        [4, 1, 0, 0]])

希望有好的建议和算法,谢谢。


可能是Can numpy bincount work with 2D arrays?的重复问题。 - jdehesa
你需要的是带有轴参数的np.bincount,但目前还没有实现(请参见问题#8495#9397)。如链接问题中所建议的,您可以暂时使用apply_along_axis - jdehesa
除非可能性为0,否则我会拒绝任何明显的循环方式。 - weidong
apply_along_axis只是另一种循环语法。 - Eelco Hoogendoorn
1个回答

0
我能想到的最少代码行数如下所示:
import numpy as np
import numpy_indexed as npi

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

row_idx = np.indices(a.shape, dtype=np.int32)[0]
axes, table = npi.Table(row_idx.flatten(), a.flatten()).count()

我没有对此进行过剖析,但它不包含任何隐藏的未向量化for循环;我怀疑您无论如何都不能使用numpy更快地完成它。虽然我也不指望它比您当前的解决方案快多少,但使用尽可能小的int类型可能会有所帮助。

请注意,此函数并不假设a的元素形成一个连续集合;轴标签在axes元组中返回;这可能是您要寻找的行为,也可能不是。不过,根据您当前的布局修改Table类中的代码应该不难。

如果速度是您最关心的问题,则您的问题可能非常适合使用numba。


结论令人惊讶,结果完全正确,但基于 group_by 统计的速度几乎是表格(1000 * 1000)的两倍,我不确定是否采用更清晰、更简洁的方式,我生成了所有的 group_by 1,目标数组并不满意。但仍然感谢您的回复。 - weidong
不确定发生了什么。表格使用的是 np.add.at,我经常发现它与 groupby.sum 使用的 np.add.reduce 相比非常缓慢;可能是这个原因。但无论如何,对于这种问题,我认为 numba 要快十倍以上。 - Eelco Hoogendoorn
谢谢您的建议,我会尝试使用Numba。 - weidong

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