如何在Pandas聚合/映射中访问MultiIndex的索引值?
解决MultiIndex DataFrame按行聚合时访问索引列的问题
问题重现
构造带MultiIndex(层级i1、i2)的DataFrame:
import pandas as pd df = pd.DataFrame( { "i1": list("abcde"), "i2": range(10, 20, 2), "c1": range(1, 11, 2), "c2": list("fghij"), } ).set_index(["i1", "i2"])
输出结果:
c1 c2 i1 i2 a 10 1 f b 12 3 g c 14 5 h d 16 7 i e 18 9 j
尝试通过自定义函数结合agg更新c1列时,因行对象无法访问索引层级i1抛出KeyError;使用reset_index后聚合,又因索引不匹配无法与原DataFrame求和。实际自定义函数包含复杂条件与副作用:
def _agg(row) -> float: import os if str(row["c2"]).startswith("f"): return float(os.environ.get(str(row["i1"]).upper(), -1)) elif not str(row["c2"]).startswith("j"): return float(os.environ.get(f"MY_VAR_{str(row['i1']).upper()}", 0)) else: return 1
可行解决方案
方案1:用assign临时添加索引列(保留原索引)
你提出的df.assign({"i1": df.index.get_level_values("i1")})是完全可行的方案,代码实现如下:
# 临时将i1索引转为列,执行聚合后与原c1列求和 df["c1"] += df.assign(i1=df.index.get_level_values("i1")).agg(_agg, axis="columns")
此方法会完整保留原MultiIndex,确保行匹配准确,无需担心求和时的索引问题。
方案2:修改函数直接从索引取值(可选)
若不想添加临时列,可在函数中通过行的name属性匹配索引值,需将索引转为DataFrame传入:
def _agg_with_idx(row, idx_df): import os i1_val = idx_df.loc[row.name, "i1"] if str(row["c2"]).startswith("f"): return float(os.environ.get(str(i1_val).upper(), -1)) elif not str(row["c2"]).startswith("j"): return float(os.environ.get(f"MY_VAR_{str(i1_val).upper()}", 0)) else: return 1 # 传入索引对应的DataFrame,通过行name匹配i1值 df["c1"] += df.apply(_agg_with_idx, axis="columns", idx_df=df.index.to_frame())
不过该方法逻辑稍复杂,不如assign直观易懂。
关于assign添加列的性能成本
对于大规模数据集,assign的内存与性能开销极低:
get_level_values返回的是原索引层级的引用,而非复制数据;assign只是将该引用关联到DataFrame,不会创建新的大规模数据结构;- 整体操作几乎不会额外占用内存,执行效率与直接操作原DataFrame接近,完全适用于大数据场景。
内容的提问来源于stack exchange,提问作者AlexisBRENON
相关产品推荐
相关产品推荐

