【问题标题】:Aggregations over specific columns of a large dataframe, with named output对大型数据框的特定列进行聚合,具有命名输出
【发布时间】:2019-08-27 03:17:05
【问题描述】:

我正在寻找一种聚合大型数据框的方法,可能使用 groupby。每个组将基于预先指定的列或正则表达式,并且聚合应生成命名输出。

这会生成一个示例数据框:

import pandas as pd
import itertools
import numpy as np

col = "A,B,C".split(',')
col1 = "1,2,3,4,5,6,7,8,9".split(',')
col2 = "E,F,G".split(',')

all_dims = [col, col1, col2]
all_keys = ['.'.join(i) for i in itertools.product(*all_dims)]
rng = pd.date_range(end=pd.Timestamp.today().date(), periods=12, freq='M')
df = pd.DataFrame(np.random.randint(0, 1000, size=(len(rng), len(all_keys))), columns=all_keys, index=rng)

上面生成了一个数据框,其中包含一年的月度数据,包含 36 列,名称如下:

['A.1.E', 'A.1.F', 'A.1.G', 'A.2.E', 'A.2.F', 'A.2.G', 'A.3.E', 'A.3.F',
       'A.3.G', 'A.4.E', 'A.4.F', 'A.4.G', 'A.5.E', 'A.5.F', 'A.5.G', 'A.6.E',
       'A.6.F', 'A.6.G', 'A.7.E', 'A.7.F', 'A.7.G', 'A.8.E', 'A.8.F', 'A.8.G',
       'A.9.E', 'A.9.F', 'A.9.G', 'B.1.E', 'B.1.F', 'B.1.G', 'B.2.E', 'B.2.F',
       'B.2.G', 'B.3.E', 'B.3.F', 'B.3.G', 'B.4.E', 'B.4.F', 'B.4.G', 'B.5.E',
       'B.5.F', 'B.5.G', 'B.6.E', 'B.6.F', 'B.6.G', 'B.7.E', 'B.7.F', 'B.7.G',
       'B.8.E', 'B.8.F', 'B.8.G', 'B.9.E', 'B.9.F', 'B.9.G', 'C.1.E', 'C.1.F',
       'C.1.G', 'C.2.E', 'C.2.F', 'C.2.G', 'C.3.E', 'C.3.F', 'C.3.G', 'C.4.E',
       'C.4.F', 'C.4.G', 'C.5.E', 'C.5.F', 'C.5.G', 'C.6.E', 'C.6.F', 'C.6.G',
       'C.7.E', 'C.7.F', 'C.7.G', 'C.8.E', 'C.8.F', 'C.8.G', 'C.9.E', 'C.9.F',
       'C.9.G']

我现在想要的是能够聚合数据框并采用某些列组合并生成命名输出。例如,一个规则可能是我将获取所有“A.*.E”列(中间有任何数字),对它们求和并生成一个名为“A.SUM.E”的命名输出列。然后对 'A.*.F'、'A.*.G' 等执行相同的操作。

我查看了 pandas 25 named aggregation,它允许我命名我的输出,但我看不到如何同时捕获正确的列组合并生成正确的输出名称。

如果您需要重塑数据框以制定可行的解决方案,那也可以。

注意,我知道我可以在 Python 循环中执行类似的操作,但我正在寻找一种 pandas 的方式来执行此操作。

【问题讨论】:

    标签: python pandas pandas-groupby


    【解决方案1】:

    不是 groupby 解决方案,它使用循环,但我认为它仍然相当优雅:首先使用集合获取唯一列 from - to 组合的列表,然后使用filter 计算总和:

    cols = sorted([(x[0],x[1]) for x in set([(x.split('.')[0], x.split('.')[-1]) for x in df.columns])])
    for c0, c1 in cols:
        df[f'{c0}.SUM.{c1}'] = df.filter(regex = f'{c0}\.\d+\.{c1}').sum(axis=1)
    

    结果:

                A.1.E  A.1.F  A.1.G  A.2.E  ...  B.SUM.G  C.SUM.E  C.SUM.F  C.SUM.G
    2018-08-31    978    746    408    109  ...     4061     5413     4102     4908
    2018-09-30    923    649    488    447  ...     5585     3634     3857     4228
    2018-10-31    911    359    897    425  ...     5039     2961     5246     4126
    2018-11-30     77    479    536    509  ...     4634     4325     2975     4249
    2018-12-31    608    995    114    603  ...     5377     5277     4509     3499
    2019-01-31    138    612    363    218  ...     4514     5088     4599     4835
    2019-02-28    994    148    933    990  ...     3907     4310     3906     3552
    2019-03-31    950    931    209    915  ...     4354     5877     4677     5557
    2019-04-30    255    168    357    800  ...     5267     5200     3689     5001
    2019-05-31    593    594    824    986  ...     4221     2108     4636     3606
    2019-06-30    975    396    919    242  ...     3841     4787     4556     3141
    2019-07-31    350    312    104    113  ...     4071     5073     4829     3717
    



    如果您想在新的 DataFrame 中获得结果,只需创建一个空的并将列添加到其中:

    result = pd.DataFrame()
    for c0, c1 in cols:
        result[f'{c0}.SUM.{c1}'] = df.filter(regex = f'{c0}\.\d+\.{c1}').sum(axis=1)
    

    更新:使用简单的groupby(在这种特殊情况下更简单):

    def grouper(col):
        c = col.split('.')
        return f'{c[0]}.SUM.{c[-1]}'
    
    df.groupby(grouper, axis=1).sum()
    

    【讨论】:

    • 谢谢,史蒂夫。这确实是一个优雅的解决方案!但我真的很想看看是否有人有一种纯粹的熊猫方式。
    • @delica:请查看我的更新,使用纯 groupby 解决方案,在这种特殊情况下更加简单。
    • 很好的解决方案 Stef!这看起来很棒!我接受了它,但如果你能解释一下如何使用 grouper 完成从输入到输出的映射,我将不胜感激。
    • 我们在这里使用按列分组(axis=1)。通常你会传递一个标签来按此行中的值进行分组,但你也可以传递一个函数作为by 参数。在这种情况下,对索引的每个值调用此函数。这允许您按相当复杂的标准进行分组(或非常简单的标准:如果此函数始终返回一个常量值,则根本不会进行分组,即您的整个数据集只是一组)。
    • 谢谢!有没有办法让列重叠?假设我想让 A+B 列产生 SUM1,然后 A+C 列产生 SUM2?我想我应该发布一个单独的问题。
    猜你喜欢
    • 1970-01-01
    • 2020-11-05
    • 2016-09-10
    • 1970-01-01
    • 1970-01-01
    • 2021-12-29
    • 2021-07-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多