基于月周总和条件替换两个Pandas DataFrame的数值
问题描述
我有两个Pandas DataFrame:
- 一个是按月份周数均分的DataFrame(2月分为4周,对应列
Feb_1至Feb_4;3月分为5周,对应列Mar_5至Mar_9) - 另一个是存储实际数据的DataFrame,包含上述对应列的实际数值
需求如下:
- 针对2月的
Feb_1至Feb_4列:若实际DataFrame中对应行的这4列数值总和为1,则用实际值替换均分DataFrame的对应数值;否则保留均分DataFrame的原有值。 - 针对3月的
Mar_5至Mar_9列:若实际DataFrame对应行的这5列数值总和为1,同样用实际值替换均分DataFrame的对应数值;否则保留原有值。
我尝试了以下代码引入实际值,但没找到完整实现方式:
equally['Feb_1_actual'] = equally['Name'].map(actual.set_index('Name')['Feb_1']) ## then get a sum and if it's equal to 1 replace the value otherwise keep the same value
解决方案
可以通过布尔掩码+批量赋值的方式高效实现,无需单独处理每一列,步骤如下:
1. 对齐两个DataFrame(按Name列匹配)
先确保两个DataFrame通过Name列对齐,避免行不匹配的问题:
# 以均分DataFrame的Name为基准,合并实际数据到对应行 actual_aligned = actual.set_index('Name').reindex(equally['Name']).reset_index()
2. 处理2月列的替换逻辑
计算实际DataFrame中每行Feb_1至Feb_4的总和,生成布尔掩码后批量替换:
# 定义2月列名列表 feb_cols = ['Feb_1', 'Feb_2', 'Feb_3', 'Feb_4'] # 生成掩码:总和为1的行标记为True feb_mask = actual_aligned[feb_cols].sum(axis=1) == 1 # 对符合条件的行,用实际值替换均分DataFrame的对应列 equally.loc[feb_mask, feb_cols] = actual_aligned.loc[feb_mask, feb_cols].values
3. 处理3月列的替换逻辑
和2月逻辑一致,仅调整列名列表即可:
# 定义3月列名列表 mar_cols = ['Mar_5', 'Mar_6', 'Mar_7', 'Mar_8', 'Mar_9'] # 生成3月列的掩码 mar_mask = actual_aligned[mar_cols].sum(axis=1) == 1 # 批量替换符合条件的行 equally.loc[mar_mask, mar_cols] = actual_aligned.loc[mar_mask, mar_cols].values
方案优势
- 批量操作避免手动逐个处理列的繁琐,新增月份只需扩展列名列表即可,扩展性强
- 利用Pandas原生的布尔掩码和
.loc赋值,比循环行/列效率高很多,适配大数据量场景 - 先对齐数据确保行匹配,避免因行顺序不一致导致的替换错误
内容的提问来源于stack exchange,提问作者rra
相关产品推荐
相关产品推荐

