【问题标题】:Efficiently sum elements of a numpy array corresponding to indices matched by another array有效地求和与另一个数组匹配的索引对应的numpy数组的元素
【发布时间】:2018-05-04 17:17:51
【问题描述】:

我想找到与另一个 numpy 匹配的索引对应的行的总和。

下面的例子更好地展示。

A=np.array(['a-1','b-1','b-1','c-2','a-1','b-1','c-2']);
b = np.array([1.21,2.34,1.2,2.8,10.0,0.9,8.4]);;

我更喜欢输出是字典,这样

d['a-1'] = 1.21 + 10.0 = 11.21
d['b-1'] = 2.34 + 1.2 + 0.9 = 4.44
d['c-2'] = 2.8 + 8.4 = 11.2

结果是 b 数组中与 A 数组中出现相同值的索引对应的元素的总和。有没有一种有效的方法来做到这一点?我的数组很大(数百万的订单)

【问题讨论】:

    标签: python arrays python-2.7 numpy


    【解决方案1】:

    方法#1

    我们可以使用np.uniquenp.bincount 的组合-

    In [48]: unq, ids = np.unique(A, return_inverse=True)
    
    In [49]: dict(zip(unq, np.bincount(ids, b)))
    Out[49]: 
    {'a-1': 11.210000000000001,
     'b-1': 4.4400000000000004,
     'c-2': 11.199999999999999}
    

    因此,np.uniqueA 中的每个字符串提供了唯一的整数映射,然后将其馈送到np.bincount,后者将这些整数用作基于bin 的加权求和的bin,权重来自b

    方法 #2(特定情况)

    假设A 中的字符串总是3 字符,更快的方法是将这些字符串转换为数字,然后将它们用作np.unique 的输入。这个想法是np.unique 处理数字比处理字符串更快。

    因此,实现将是 -

    In [141]: n = A.view(np.uint8).reshape(-1,3).dot(256**np.arange(3))
    
    In [142]: unq, st, ids = np.unique(n, return_index=1, return_inverse=1)
    
    In [143]: dict(zip(A[st], np.bincount(ids, b)))
    Out[143]: 
    {'a-1': 11.210000000000001,
     'b-1': 4.4400000000000004,
     'c-2': 11.199999999999999}
    

    神奇的部分是viewing在重塑后仍然是一个视图,因此应该非常有效:

    In [150]: np.shares_memory(A,A.view(np.uint8).reshape(-1,3))
    Out[150]: True
    

    或者我们可以使用np.uniqueaxis参数(在1.13.0中添加的功能)-

    In [160]: A2D = A.view(np.uint8).reshape(-1,3)
    
    In [161]: unq, st, ids = np.unique(A2D, axis=0, return_index=1, return_inverse=1)
    
    In [162]: dict(zip(A[st], np.bincount(ids, b)))
    Out[162]: 
    {'a-1': 11.210000000000001,
     'b-1': 4.4400000000000004,
     'c-2': 11.199999999999999}
    

    【讨论】:

      【解决方案2】:

      另一种方法,使用pandas

      import pandas as pd
      df = pd.DataFrame(data=[pd.Series(A),pd.Series(b)]).transpose()
      res = df.groupby(0).sum()
      

      给予

      res
      Out[62]: 
               1
      0         
      a-1  11.21
      b-1   4.44
      c-2  11.20
      

      你可以像这样得到你想要的字典:

      res_dict = res[1].to_dict()
      

      这给了

      Out[64]: 
      {'a-1': 11.210000000000001,
       'b-1': 4.4400000000000004,
       'c-2': 11.199999999999999}
      

      【讨论】:

        【解决方案3】:

        numpy_indexed 包(dsiclaimer:我是它的作者)包含以高效和优雅的方式执行这些类型的操作的功能:

        import numpy_indexed as npi
        k, v = npi.group_by(A).sum(b)
        d = dict(zip(k, v))
        

        我觉得 pandas 的分组语法很笨拙;并且没有必要将您的数据重新组织成一个新的数据结构来执行这样的基本操作。

        【讨论】:

        • 尽管我同意转换为 pandas 格式的笨拙,但您可能想在答案中添加您是该软件包的开发人员,或者它可能被标记为 this answer
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-29
        • 1970-01-01
        • 2015-03-23
        • 1970-01-01
        • 2012-01-05
        相关资源
        最近更新 更多