优化Pandas标记同ID正负Saldo配对行的高效实现方案问询
高效标记Pandas DataFrame中匹配的行对
需求说明
我有一个约5万行的Pandas DataFrame,仅需关注id和Saldo列,需要标记满足以下条件的行对:
- 两行
id相同 Saldo值互为相反数
注意:
- DataFrame未按
id排序 - 单个
id可对应多组匹配行对 - 若某个
id对应行数为奇数(比如3行中有2个正值、1个绝对值相等的负值),仅标记一组配对行(如示例中id='I'仅标记索引12和13的行)
当前用双重循环实现但耗时超1天,掩码方法存在“trio bug”(错误标记三元组中的未配对行),需要矢量化、分组排序类的高效方案。
示例数据
import pandas as pd data = {'id': ['A', 'B', 'A', 'D', 'A', 'A', 'F', 'F', 'F', 'G', 'H', 'H', 'I','I','I'], 'Saldo': [-2209.00, -17391.00, 2209.00, -2209.00, 2209.00, -2209.00, -17588.51, -18457.71, -104179.79, -16957.20, 23644.95, -23644.95, -2209.00, 2209.00, -2209.00]} df = pd.DataFrame(data)
高效实现方案
核心思路是按id分组,对每组内的Saldo按正负拆分后配对,避免重复标记或错误标记未配对行,全程用矢量化操作,无需循环:
import pandas as pd # 初始化Reconciled列 df['Reconciled'] = '' # 按id分组处理 for _, group in df.groupby('id'): # 拆分正负值的行索引 pos_idx = group[group['Saldo'] > 0].index neg_idx = group[group['Saldo'] < 0].index # 按绝对值排序,确保能一一配对 pos_sorted = group.loc[pos_idx].sort_values('Saldo') neg_sorted = group.loc[neg_idx].sort_values('Saldo', key=lambda x: -x) # 负数值按绝对值从小到大排 # 取两者中较小的长度,得到可配对的数量 pair_count = min(len(pos_sorted), len(neg_sorted)) # 标记配对的行 if pair_count > 0: # 标记正数值的前pair_count行 df.loc[pos_sorted.index[:pair_count], 'Reconciled'] = 'Reconciled' # 标记负数值的前pair_count行 df.loc[neg_sorted.index[:pair_count], 'Reconciled'] = 'Reconciled'
方案说明
- 分组处理:按
id分组后,每组独立处理,避免跨id匹配 - 拆分正负:将每组内的行按Saldo正负拆分,方便后续配对
- 排序配对:对正数值按大小升序,负数值按绝对值升序(即负数值本身降序),确保绝对值相等的行能对应上
- 限制配对数量:取正负行数量的最小值,只标记能完全配对的行,避免标记未配对的单行(解决trio bug)
验证示例结果
运行后示例DataFrame的Reconciled列结果:
| 索引 | id | Saldo | Reconciled |
|---|---|---|---|
| 0 | A | -2209.00 | Reconciled |
| 1 | B | -17391.00 | |
| 2 | A | 2209.00 | Reconciled |
| 3 | D | -2209.00 | |
| 4 | A | 2209.00 | Reconciled |
| 5 | A | -2209.00 | Reconciled |
| 6 | F | -17588.51 | |
| 7 | F | -18457.71 | |
| 8 | F | -104179.79 | |
| 9 | G | -16957.20 | |
| 10 | H | 23644.95 | Reconciled |
| 11 | H | -23644.95 | Reconciled |
| 12 | I | -2209.00 | Reconciled |
| 13 | I | 2209.00 | Reconciled |
| 14 | I | -2209.00 |
完全符合需求:id='A'的4行全部配对,id='I'仅标记一组配对行,无未配对行被错误标记。
内容的提问来源于stack exchange,提问作者Pieter de Wit
相关产品推荐
相关产品推荐

