如何在Pandas中无循环实现自定义索引子集的聚合操作?
问题描述
假设我有一个Pandas DataFrame,示例代码如下:
import pandas as pd df = pd.DataFrame(columns=["A", "B"], data = [(1, 2), (4, 5), (7, 8), (10, 11)])
同时有一组自定义索引子集:
inds = [(0, 1, 3), (0, 1, 2), (1, 2, 3)]
希望根据这些索引子集进行聚合操作(比如求均值),期望得到的结果如下:
| A | B |
|---|---|
df.loc[inds[0], "A"].mean() | df.loc[inds[0], "B"].mean() |
df.loc[inds[1], "A"].mean() | df.loc[inds[1], "B"].mean() |
df.loc[inds[2], "A"].mean() | df.loc[inds[2], "B"].mean() |
是否可以不编写循环,仅使用Pandas原生方法实现该操作?这和df.groupby后调用.agg的逻辑类似,但我没找到通过自定义索引集合创建GroupBy对象的方法。
解决方案
可以通过Pandas原生方法结合numpy实现无循环的自定义分组聚合,以下是三种高效方案:
方法1:构造分组映射实现groupby
核心思路是给每个原索引分配对应的分组ID,再通过分组ID完成聚合:
import pandas as pd df = pd.DataFrame(columns=["A", "B"], data = [(1, 2), (4, 5), (7, 8), (10, 11)]) inds = [(0, 1, 3), (0, 1, 2), (1, 2, 3)] # 构建原索引到分组ID的映射 group_map = {} for group_id, idx_list in enumerate(inds): for idx in idx_list: group_map.setdefault(idx, []).append(group_id) # 转换为可用于groupby的Series(展开多分组映射) group_series = pd.Series(group_map).explode().astype(int) # 按分组ID聚合计算均值 result = df.loc[group_series.index].groupby(group_series).mean() print(result)
输出结果:
A B 0 5.000000 6.000000 1 4.000000 5.000000 2 7.000000 8.000000
该方案支持同一个原索引属于多个分组的场景,会自动将对应行分配到所有关联分组中参与计算。
方法2:拼接分组数据后聚合
如果分组逻辑简单,可直接提取每个分组的数据并标记分组ID,再合并聚合:
# 为每个分组的数据添加分组标记,存入列表 dfs = [] for group_id, idx_list in enumerate(inds): temp_df = df.loc[idx_list].assign(group=group_id) dfs.append(temp_df) # 合并后按分组标记聚合 result = pd.concat(dfs).groupby("group").mean() print(result)
此方法逻辑直观,易理解,分组数量不多时性能与方法1相当。
方法3:numpy广播加速(适合大型数据集)
处理超大规模数据时,可直接用numpy的广播机制跳过Pandas分组逻辑,提升计算速度:
import numpy as np # 将索引子集转为numpy数组 inds_np = np.array(inds) # 提取对应数据并计算均值,转换为DataFrame result = pd.DataFrame( np.mean(df.values[inds_np], axis=1), columns=df.columns ) print(result)
该方案完全基于numpy的向量运算,是三种方法中速度最快的,适合数据量较大的场景。
内容的提问来源于stack exchange,提问作者DimB
相关产品推荐
相关产品推荐

