Pandas 动态聚合列

Pandas Aggregate columns dynamically

我的目标是聚合类似于 SAS 的“proc summary using types”的数据 我的起始 pandas 数据框可能看起来像这样,其中数据库已经完成了所有 dimensions/classification 变量的原始分组,并且对措施做了一些聚合功能。 所以在 sql 这看起来像

select gender, age, sum(height), sum(weight)
from db.table
group by gender, age
gender age height weight
F 19 70 123
M 24 72 172

然后我想使用 pandas 来汇总数据,根据不同的分组依据计算汇总行来得出这个结果。

gender age height weight
. . 142 295
. 19 70 123
. 24 72 172
F . 70 123
M . 72 172
F 19 70 123
M 24 72 172

其中第一行是没有分组依据的 agg 第 2 行和第 3 行按年龄分组 4 和 5 只按性别分类 然后只是正常的行

我当前的代码如下所示

# normally dynamic just hard coded for this example
measures = {'height':{'stat':'sum'}, 'age':{'stat':'sum'}}
msr_config_dict = {}
for measure in measures:
    if measure in message_measures:
       stat = measures[measure]['stat']
       msr_config_dict[measure] = pd.NamedAgg(measure, stat)

# compute agg with no group by as starting point
df=self.df.agg(**msr_config_dict)
dimensions = ['gender','age'] # also dimensions is dynamic in real life
dim_vars = []
for dim in dimensions:
    dim_vars.append(dim)
    if len(dim_vars) > 1:
       # compute agg of compound dimensions
       df_temp = self.df.groupby(dim_vars, as_index=False).agg(msr_config_dict)
       df = df.append(df_temp, ignore_index=True)
    # always compute agg of solo dimension
    df_temp = self.df.groupby(dim, as_index=False).agg(msr_config_dict)
    df = df.append(df_temp, ignore_index=True)

使用此代码我得到 AttributeError: 'height' is not a valid function for 'Series' object

agg函数的输入我也试过了 {'height':[('height', 'sum')], 'weight':[('weight', 'sum')]} 我正在尝试计算所有高度的总和并命名输出高度。这也有一个属性错误。 我知道我只会为每个度量计算一个聚合函数,所以我想动态构建 pandas 聚合函数的输入,并始终将统计重命名为自身,这样我就可以将它附加到我所在的数据框使用摘要行构建。

我是 SAS 背景的 pandas 新手。 任何帮助将不胜感激。

IIUC:

cols = ['height', 'weight']

out = pd.concat([df[cols].sum(0).to_frame().T,
                 df.groupby('age')[cols].sum().reset_index(),
                 df.groupby('gender')[cols].sum().reset_index(),
                 df], ignore_index=True)[df.columns].fillna('.')

输出:

>>> out
  gender   age  height  weight
0      .     .     142     295
1      .  19.0      70     123
2      .  24.0      72     172
3      F     .      70     123
4      M     .      72     172
5      F  19.0      70     123
6      M  24.0      72     172

这里有一个更灵活的解决方案,它扩展了 . You can use itertools.combinations 的解决方案以创建所有尺寸组合和所有可能的组合长度。

from itertools import combinations

# your input
measures = {'height':{'stat':'sum'}, 'weight':{'stat':'min'}}
dimensions = ['gender','age'] 

# change the nested dictionary
msr_config_dict = {key:val['stat'] for key, val in measures.items()}

# concat all possible aggregation
res = pd.concat(
    # case with all aggregated
    [df.agg(msr_config_dict).to_frame().T] 
    # cases at least one column to aggregate over
    + [df.groupby(list(_dimCols)).agg(msr_config_dict).reset_index()
       # for combinations of length 1, 2.. depending on the number of dimensions
       for nb_cols in range(1, len(dimensions))
       # all combinations of the specific lenght
       for  _dimCols in combinations(dimensions, nb_cols)]
    # original dataframe
    + [df],
    ignore_index=True)[df.columns].fillna('.')

print(res)
#   gender   age  height  weight
# 0      .     .     142     123
# 1      F     .      70     123
# 2      M     .      72     172
# 3      .  19.0      70     123
# 4      .  24.0      72     172
# 5      F  19.0      70     123
# 6      M  24.0      72     172