【问题标题】:Sum rows where value equal in column对列中值相等的行求和
【发布时间】:2015-07-14 11:56:06
【问题描述】:

如何对 numpy 数组的第一列中具有相等值的行求和?例如:

In: np.array([[1,2,3],
             [1,4,6], 
             [2,3,5],
             [2,6,2],
             [3,4,8]])

Out: [[1,6,9], [2,9,7], [3,4,8]]

任何帮助将不胜感激。

【问题讨论】:

  • 第一列总是排序吗?

标签: python numpy sum row


【解决方案1】:

Pandas 有一个非常强大的 groupby 功能,这让这变得非常简单。

import pandas as pd

n = np.array([[1,2,3],
             [1,4,6], 
             [2,3,5],
             [2,6,2],
             [3,4,8]])

df = pd.DataFrame(n, columns = ["First Col", "Second Col", "Third Col"])

df.groupby("First Col").sum()

【讨论】:

  • 感谢您的帮助。我知道熊猫解决方案,我正在寻找一个特定的 numpy 解决方案。我可能最终会选择 pd。
  • 您可以通过使用 itertools 或字典将行组合在一起以避免 Pandas 来执行“手动”。希望比我聪明的人发帖,因为如果有其他方法我也想学习它:)
【解决方案2】:

尝试使用熊猫。按第一列分组,然后逐行求和。像

df.groupby(df.ix[:,1]).sum()

【讨论】:

    【解决方案3】:

    方法#1

    这是基于 np.bincount 的 numpythonic 矢量化方式 -

    # Initial setup             
    N = A.shape[1]-1
    unqA1, id = np.unique(A[:, 0], return_inverse=True)
    
    # Create subscripts and accumulate with bincount for tagged summations
    subs = np.arange(N)*(id.max()+1) + id[:,None]
    sums = np.bincount( subs.ravel(), weights=A[:,1:].ravel() )
    
    # Append the unique elements from first column to get final output
    out = np.append(unqA1[:,None],sums.reshape(N,-1).T,1)
    

    样本输入、输出-

    In [66]: A
    Out[66]: 
    array([[1, 2, 3],
           [1, 4, 6],
           [2, 3, 5],
           [2, 6, 2],
           [7, 2, 1],
           [2, 0, 3]])
    
    In [67]: out
    Out[67]: 
    array([[  1.,   6.,   9.],
           [  2.,   9.,  10.],
           [  7.,   2.,   1.]])
    

    方法 #2

    这是另一个基于 np.cumsumnp.diff 的 -

    # Sort A based on first column
    sA = A[np.argsort(A[:,0]),:]
    
    # Row mask of where each group ends
    row_mask = np.append(np.diff(sA[:,0],axis=0)!=0,[True])
    
    # Get cummulative summations and then DIFF to get summations for each group
    cumsum_grps = sA.cumsum(0)[row_mask,1:]
    sum_grps = np.diff(cumsum_grps,axis=0)
    
    # Concatenate the first unique row with its counts
    counts = np.concatenate((cumsum_grps[0,:][None],sum_grps),axis=0)
    
    # Concatenate the first column of the input array for final output
    out = np.concatenate((sA[row_mask,0][:,None],counts),axis=1)
    

    基准测试

    这是迄今为止针对该问题提出的基于 numpy 的方法的一些运行时测试 -

    In [319]: A = np.random.randint(0,1000,(100000,10))
    
    In [320]: %timeit cumsum_diff(A)
    100 loops, best of 3: 12.1 ms per loop
    
    In [321]: %timeit bincount(A)
    10 loops, best of 3: 21.4 ms per loop
    
    In [322]: %timeit add_at(A)
    10 loops, best of 3: 60.4 ms per loop
    
    In [323]: A = np.random.randint(0,1000,(100000,20))
    
    In [324]: %timeit cumsum_diff(A)
    10 loops, best of 3: 32.1 ms per loop
    
    In [325]: %timeit bincount(A)
    10 loops, best of 3: 32.3 ms per loop
    
    In [326]: %timeit add_at(A)
    10 loops, best of 3: 113 ms per loop
    

    似乎Approach #2: cumsum + diff 的表现相当不错。

    【讨论】:

      【解决方案4】:

      在您的朋友np.uniquenp.add.at 的帮助下:

      >>> unq, unq_inv = np.unique(A[:, 0], return_inverse=True)
      >>> out = np.zeros((len(unq), A.shape[1]), dtype=A.dtype)
      >>> out[:, 0] = unq
      >>> np.add.at(out[:, 1:], unq_inv, A[:, 1:])
      
      >>> out  # A was the OP's array
      array([[1, 6, 9],
             [2, 9, 7],
             [3, 4, 8]])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-03
        相关资源
        最近更新 更多