如何优雅填充Pandas DataFrame中缺失的行列组合?
填充Pandas DataFrame的缺失组合行
问题背景
现有两个列表:
a = ["a", "b"] # column a b = ["e", "f"] # column b
以及初始DataFrame:
import pandas as pd data_frame = pd.DataFrame([{"a": "a", "b": "e", "c": 5}])
对其分组聚合后:
result = data_frame.groupby(["a", "b"])["c"].sum().reset_index()
得到的结果仅包含一行数据:
| a | b | c |
|---|---|---|
| a | e | 5 |
需要补充a和b的所有笛卡尔积组合,最终得到包含4行的DataFrame:
| a | b | c |
|---|---|---|
| a | e | 5 |
| a | f | 0 |
| b | e | 0 |
| b | f | 0 |
原实现用嵌套循环+concat的方式,代码不够简洁高效:
for i in a: for j in b: if i not in result["a"] and j not in result["b"]: result = pd.concat([ result, pd.DataFrame([{"a": i, "b": j, "c": 0}]) ])
更优解决方案
方法1:利用MultiIndex.from_product生成全组合后重索引
先生成a和b的所有可能组合,再让聚合结果匹配这个全索引,缺失值直接填充为0:
# 生成包含所有组合的多级索引 full_combinations = pd.MultiIndex.from_product([a, b], names=["a", "b"]) # 分组聚合得到Series(以a、b为索引) agg_series = data_frame.groupby(["a", "b"])["c"].sum() # 重索引并填充0,最后转为DataFrame final_result = agg_series.reindex(full_combinations, fill_value=0).reset_index()
方法2:全组合DataFrame与聚合结果左连接
先生成全组合的空DataFrame,再和聚合结果做左连接,最后把缺失的c值填充为0:
# 生成所有组合的DataFrame full_df = pd.DataFrame(pd.MultiIndex.from_product([a, b], names=["a", "b"]).tolist(), columns=["a", "b"]) # 左连接后填充缺失值,确保c列为整数类型 final_result = full_df.merge(result, on=["a", "b"], how="left").fillna({"c": 0}).astype({"c": int})
方法3:用pivot_table一步生成
利用透视表的特性,直接指定行、列和聚合函数,同时设置填充值为0,最后堆叠转为目标格式:
# 创建透视表,自动补全所有组合并填充0 pivot_df = data_frame.pivot_table(index="a", columns="b", values="c", aggfunc="sum", fill_value=0) # 堆叠列索引,重置索引并重命名列 final_result = pivot_df.stack().reset_index(name="c")
这几种方法都避免了循环和多次拼接操作,代码更简洁,当a、b的元素数量较多时,执行效率也会远高于原实现。
内容的提问来源于stack exchange,提问作者Christian Weiss
相关产品推荐
相关产品推荐

