如何基于user_id键对两个Pandas DataFrame执行除法运算?
嘿,这个问题我之前处理类似需求时碰到过!其实不用折腾分组操作,Pandas有更简洁直接的方式解决,先给你理清楚思路:
首先先把两个示例DataFrame的代码贴出来,方便大家复现场景:
import pandas as pd # 第一个包含用户、子项和得分的DataFrame df1 = pd.DataFrame({ 'user_id': [39, 39, 40, 40, 40], 'sub_id': [16, 4, 1, 2, 3], 'score': [1, 1, 3, 3, 3] }) # 第二个包含用户总得分的DataFrame df2 = pd.DataFrame({ 'user_id': [39, 40], 'score': [2, 30] })
你说的用div操作只返回首个匹配项的问题,本质是因为div默认按索引对齐,而df2的索引是user_id,但df1的索引是默认的0、1、2...,只有df1中索引和df2索引(user_id)一致的行才能匹配上,其余自然返回NaN。
最简洁的解决方案:用map映射计算
先把df2转换成以user_id为键的Series,然后用df1的user_id列映射对应的用户总得分,最后做除法即可:
# 构建user_id到总得分的映射Series user_total_scores = df2.set_index('user_id')['score'] # 逐行计算归一化得分 df1['normalized_score'] = df1['score'] / df1['user_id'].map(user_total_scores)
运行后得到的结果完全符合预期:
| user_id | sub_id | score | normalized_score |
|---|---|---|---|
| 39 | 16 | 1 | 0.5 |
| 39 | 4 | 1 | 0.5 |
| 40 | 1 | 3 | 0.1 |
| 40 | 2 | 3 | 0.1 |
| 40 | 3 | 3 | 0.1 |
备选方案:先合并再计算
如果需要保留df2中的其他列(假设后续有扩展需求),可以先通过merge按user_id合并两个DataFrame,再做除法:
# 合并两个DF,用后缀区分原得分和用户总得分 merged_df = df1.merge(df2, on='user_id', suffixes=('_sub', '_total')) # 计算归一化得分 merged_df['normalized_score'] = merged_df['score_sub'] / merged_df['score_total'] # 整理回原df1的结构(可选) result_df = merged_df[['user_id', 'sub_id', 'score_sub', 'normalized_score']].rename(columns={'score_sub': 'score'})
关于分组操作
分组当然也能实现,但代码更繁琐,性能也不如上面两种方法(数据量大时差距明显),这里也贴出来供你参考:
def normalize_group(group): # 获取当前分组对应的用户总得分 total_score = df2.loc[df2['user_id'] == group.name, 'score'].iloc[0] group['normalized_score'] = group['score'] / total_score return group result_df = df1.groupby('user_id').apply(normalize_group)
总结一下,优先用map的方法,简洁高效;merge适合有扩展需求的场景;分组操作除非特殊情况,否则没必要用~
内容的提问来源于stack exchange,提问作者Nikhil Verma
相关产品推荐
相关产品推荐

