【问题标题】:How to sum a column grouped by other columns in a list?如何对列表中由其他列分组的列求和?
【发布时间】:2018-09-07 05:55:01
【问题描述】:

我有一个清单如下。

[['Andrew', '1', '9'], ['Peter', '1', '10'], ['Andrew', '1', '8'], ['Peter', '1', '11'], ['Sam', '4', '9'], ['Andrew', '2', '2']]

我想总结最后一列按其他列分组。结果是这样的

[['Andrew', '1', '17'], ['Peter', '1', '21'], ['Sam', '4', '9'], ['Andrew', '2', '2']]

这仍然是一个列表。

在实际实践中,我总是想总结由许多其他列分组的最后一列。有没有办法在 Python 中做到这一点?非常感谢。

【问题讨论】:

    标签: python list pandas dataframe pandas-groupby


    【解决方案1】:

    按除最后一列之外的所有列动态分组:

    In [24]: df = pd.DataFrame(data)
    
    In [25]: df.groupby(df.columns[:-1].tolist(), as_index=False).agg(lambda x: x.astype(int).sum()).values.tolist()
    Out[25]: [['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]
    

    【讨论】:

    • [0,1]代表第一列和第二列吗?
    • @Deepleeqe,是的,我还添加了另一个版本,它可以为任意数量的列动态完成...
    【解决方案2】:

    这是通过collections.defaultdict 实现的 O(n) 解决方案,适用于任意数量的键。

    如果您想要的输出是一个列表,那么这可能比通过 Pandas 的解决方案更可取,后者需要转换为非标准类型。

    from collections import defaultdict
    
    lst = [['Andrew', '1', '9'], ['Peter', '1', '10'], ['Andrew', '1', '8'],
           ['Peter', '1', '11'], ['Sam', '4', '9'], ['Andrew', '2', '2']]
    
    d = defaultdict(int)
    
    for *keys, val in lst:
        d[tuple(keys)] += int(val)
    
    res = [[*k, v] for k, v in sorted(d.items())]
    

    结果

    [['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]
    

    说明

    • 循环浏览您的列表,定义键/值并添加到您的defaultdict 列表中。
    • 使用列表推导将字典转换为所需的输出。

    【讨论】:

      【解决方案3】:

      Op1

      您可以传递一个索引sum 并添加到列表转换回列表

      pd.DataFrame(L).\
         set_index([0,1])[2].astype(int).sum(level=[0,1]).\
              reset_index().values.tolist()
      Out[78]: [['Andrew', '1', 17], ['Peter', '1', 21], ['Sam', '4', 9], ['Andrew', '2', 2]]
      

      Op2

      对于列表列表,您可以使用来自itertoolsgroupby

      from itertools import groupby
      [k+[sum(int(v) for _,_, v in g)] for k, g in groupby(sorted(l), key = lambda x: [x[0],x[1]])]
      Out[98]: [['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]
      

      【讨论】:

        【解决方案4】:

        创建为DataFrame并聚合第三列由第一列和第二列转换为整数,最后转换回lists:

        df = pd.DataFrame(L)
        L = df[2].astype(int).groupby([df[0], df[1]]).sum().reset_index().values.tolist()
        print (L)
        [['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]
        

        以及defaultdict 的解决方案,仅限 python 3.x:

        from collections import defaultdict
        
        d = defaultdict(int)
        #https://stackoverflow.com/a/10532492
        for *head, tail in L:
            d[tuple(head)] += int(tail)
        
        d = [[*i, j] for i, j in sorted(d.items())]
        print (d)
        [['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]
        

        【讨论】:

          【解决方案5】:

          pd.factorizenp.bincount

          f, u = pd.factorize([tuple(x[:-1]) for x in data])
          v = np.array([x[-1] for x in data], int)
          
          [list(k) + [int(v)] for k, v in zip(u, np.bincount(f, v))]
          
          [['Andrew', '1', 17], ['Peter', '1', 21], ['Sam', '4', 9], ['Andrew', '2', 2]]
          

          【讨论】:

            【解决方案6】:

            加了我的 2 美分。这两个都使用groupbyagg

            V1:引入了新的求和函数。

            sum=lambda x: x.astype(int).sum()
            print(df.groupby([0,1], as_index=False).agg({2: sum}).values.tolist())
            

            V2:将列转换为数字

            df[2] = pd.to_numeric(df[2])
            print(df.groupby([0,1], as_index=False).agg({2: sum}).values.tolist())
            

            并且会返回:

            [['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]
            

            【讨论】:

              猜你喜欢
              • 2012-01-03
              • 1970-01-01
              • 2021-09-01
              • 1970-01-01
              • 2020-05-30
              • 2021-01-09
              • 2022-08-18
              • 1970-01-01
              相关资源
              最近更新 更多