我正在try 计算数字数组中列子集的聚合指标(例如,平均值、中位数、和).

以此数组为例:

1 6 3 4
2 3 4 5
1 4 5 6
3 5 6 7

我有一组簇,它们是列索引的列表,如下所示:

clusters = [[0, 1], [2], [3]]

数组和簇索引列表都可以很大,并且我可以保证数组中的每一列只属于一个簇,即簇列表中没有重复项.列表中的索引不一定是有序的,也就是说,[[0, 3], [2, 1]]也是一个有效的集群.

例如,我要找的是对每个集群的值进行求和--上例的结果如下所示:

[25, 18, 22]

Python中的一个简单实现可能看起来像这样:

import numpy as np

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

clusters = [[0, 1], [2], [3]]

result = np.array([arr[:,c_indices].sum() for c_indices in clusters])
# array([25, 18, 22])

我的问题是矩阵和集群的数量可能会变得非常大,我希望避免在Python中循环,而是出于性能原因在NumPy的C实现中尽可能多地保留这些内容.

Are there more efficient ways of doing this? (理想情况下与最小值、最大值、中位数、平均值和总和兼容)

推荐答案

首先,对NumPy中的列进行求和,然后只对结果求和:

n = 10**4
arr = np.random.rand(n,n)
clusters = [[random.randint(0,n-1) for _ in range(random.randint(0,n))] 
             for _ in range(n//100)]
%%timeit 
arr_sumed = arr.sum(0)
[arr_sumed[c_indices].sum() for c_indices in clusters]

每循环38.6毫秒±1.08毫秒(平均值±标准戴夫.共7次运行,每次10次循环)

%timeit [arr[:,c_indices].sum() for c_indices in clusters]

S每环27.3ms±382ms(平均值±标准戴夫.共7次运行,每次1次循环)

如果我想要一个中位数而不是总和,该怎么办?

好吧,我希望其他人会想出一个更好的解决方案,但你可以做的一件事是提前对列进行排序.然后,你可以通过将排序列表中的索引相加来找到一个数字的索引.最后,你对中位数进行二进制搜索:

n = 10**4
arr = np.random.rand(n,n)
clusters = [np.array([random.randint(0,n-1) for i in range(random.randint(0,n))]) for j in range(n//100)]
%%time
def median_from_sorted_arrays(arr_sorted, arr_min, arr_max, c_indices):
    n = len(arr_min)*len(c_indices)
    a = min(arr_min[c_indices])
    b = max(arr_max[c_indices])

    while True:
        k = sum(np.searchsorted(arr_sorted[i], (a+b)/2) for i in c_indices)
        if k/n < 0.499:
            a = (a+b)/2
        elif k/n > 0.501:
            b = (a+b)/2    
        else:
            return (a+b)/2

arr_sorted = np.sort(arr, 0)
arr_min = np.min(arr, 0)
arr_max = np.max(arr, 0)

[median_from_sorted_arrays(arr_sorted, arr_min, arr_max,c_indices) for c_indices in clusters]

这花了13.7秒,而天真的方法只花了1分43秒.

请注意,尽管二分搜索应该总是有效的,并给出一个完美的解决方案,但我没有花时间计算出正确的停止标准,使这个中位数成为一个近似值.

Python相关问答推荐

将DF中的名称与另一DF拆分并匹配并返回匹配的公司

使用numpy提取数据块

点到面的Y距离

沿着数组中的轴计算真实条目

如果值不存在,列表理解返回列表

用合并列替换现有列并重命名

C#使用程序从Python中执行Exec文件

如何在类和classy-fastapi -fastapi- followup中使用FastAPI创建路由

计算组中唯一值的数量

如何在Python数据框架中加速序列的符号化

Pandas计数符合某些条件的特定列的数量

什么是最好的方法来切割一个相框到一个面具的第一个实例?

旋转多边形而不改变内部空间关系

如何在PySide/Qt QColumbnView中删除列

BeautifulSoup:超过24个字符(从a到z)的迭代失败:降低了首次深入了解数据集的复杂性:

如何在Python 3.9.6和MacOS Sonoma 14.3.1下安装Pyregion

从嵌套极轴列的列表中删除元素

当我定义一个继承的类时,我可以避免使用`metaclass=`吗?

函数()参数';代码';必须是代码而不是字符串

pyspark where子句可以在不存在的列上工作