Python pandas如何按匹配ID跨表做除法计算并生成指定列
实现步骤
直接按需求做关联计算即可,步骤如下:
- 先固定
Jan到Sep的9个月份列名,后续批量处理不用重复写代码 - 处理第二个除数表:只保留ID和9个月份列,把所有月份列重命名为
D+月份名(比如Jan改成DJan),避免和原表的同名字段冲突 - 用左连接以
ID为关联键,把处理好的除数列拼到第一个原始表上,保证原始表的所有行都完整保留,不会因为第二个表有多余ID丢失数据 - 遍历每个月份列,用原始表的月份值除以对应D列的除数,得到
R+月份名的结果列 - 最后调整列顺序,严格按照要求排列:原始表原有字段在前,中间是D开头的除数列,最后是R开头的计算结果列
完整可运行代码
import pandas as pd # 初始化第一个原始DataFrame d = {'Name' : pd.Series(['A', 'A', 'A','B', 'B', 'B', 'C', 'D', 'D']), 'ID' : pd.Series(['10', '11', '12','13', '10', '12','14','10','12']), 'Jan' : pd.Series([100,200,300,200,400,600,20,50,100]), 'Feb' : pd.Series ([100,150,200,100,200,300,200,50,100]), 'Mar' : pd.Series([100,200,300,200,400,400,20,40,50]), 'Apr' : pd.Series([10,250,200,100,200,400,210,105,100]), 'May' : pd.Series([100,100,100,200,200,300,200,60,50]), 'Jun' : pd.Series([100,200,200,200,100,200,200,410,50]), 'Jul' : pd.Series([50,100,240,200,200,450,200,410,50]), 'Aug' : pd.Series([100,100,200,100,200,100,120,140,150]), 'Sep' : pd.Series([100,100,200,100,200,100,100,140,150]), 'YES' : pd.Series(['Y','N','Y','N','Y','Y','N','N','N'])} newdf = pd.DataFrame(d) # 初始化第二个除数DataFrame d2 = {'ID' : pd.Series(['10', '11', '12','13', '14','17','20','21','50']), 'Jan' : pd.Series([10,20,30,20,40,60,2,5,10]), 'Feb' : pd.Series([10,15,20,10,20,30,20,5,10]), 'Mar' : pd.Series([10,20,30,20,40,40,2,4,5]), 'Apr' : pd.Series([15,10,20,10,10,10,12,14,15]), 'May' : pd.Series([10,25,20,10,20,40,21,15,10]), 'Jun' : pd.Series([15,10,20,10,10,10,12,14,15]), 'Jul' : pd.Series([2,2,2,0,2,2,3,2,2]), 'Aug' : pd.Series( [2,2,2,20,2,1,2,2,2]), 'Sep' : pd.Series( [3,0,2,2,2,1,2,5,2]), 'YES' : pd.Series(['Y','N','Y','N','Y','','','NS'])} newdf1 = pd.DataFrame(d2) # 核心处理逻辑 month_cols = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep'] # 预处理除数表,重命名月份列为D开头 divisor_df = newdf1[['ID'] + month_cols].rename(columns={col:f'D{col}' for col in month_cols}) # 左连接保留原表所有行 result = newdf.merge(divisor_df, on='ID', how='left') # 批量计算除法结果列 for col in month_cols: result[f'R{col}'] = result[col] / result[f'D{col}'] # 调整列顺序匹配要求 original_cols = ['Name','ID'] + month_cols + ['YES'] result = result[original_cols + [f'D{col}' for col in month_cols] + [f'R{col}' for col in month_cols]]
结果验证
运行代码后取索引为5的行查看,输出和给出的预期完全一致:
- 该行对应Name为B、ID为12,原始Jan值600除以DJan值30得到RJan=20
- Feb值300除以DFeb值20得到RFeb=15
- Mar值400除以DMar值30得到RMar≈13.33
- 其余月份计算结果和预期完全匹配
注意:测试数据中存在除数为0的场景(比如ID=13的DJul=0、ID=11的DSep=0),默认计算会得到inf值,如果需要把这类异常值替换为空或者自定义值,可以把计算R列的代码改成
result[f'R{col}'] = result[col].div(result[f'D{col}'].replace(0, pd.NA)),除0场景就会返回空值。
内容的提问来源于stack exchange,提问作者thangaraj1980
相关产品推荐
相关产品推荐

