Pandas按id匹配正负金额后筛选name字符串相似度最高行对的方法
实现思路
- 对筛选后的DataFrame按id分组,每组内拆分出正金额、负金额两个子集
- 遍历每组内的所有正金额行,针对每个正金额,筛选出组内金额为其相反数的所有负金额候选行
- 计算当前正金额行的name与所有候选负金额行name的字符串相似度,保留相似度最高的负金额行
- 收集所有保留的正负行对的索引,去重后取出对应行即为最终结果
完整可运行代码
import pandas as pd from difflib import SequenceMatcher # 字符串相似度计算函数,可按需替换为Jaccard等其他指标 def calc_str_similarity(a, b): return SequenceMatcher(None, a, b).ratio() def filter_best_match(df_group): # 拆分当前组正负金额行 pos_df = df_group[df_group['amount'] > 0].reset_index() neg_df = df_group[df_group['amount'] < 0].reset_index() keep_indices = set() for _, pos_row in pos_df.iterrows(): target_neg_amount = -pos_row['amount'] # 筛选金额匹配的负金额候选行 candidates = neg_df[neg_df['amount'] == target_neg_amount] if candidates.empty: continue # 计算所有候选的相似度,取最高的配对 candidates['sim'] = candidates['name'].apply(lambda x: calc_str_similarity(pos_row['name'], x)) best_neg = candidates.sort_values('sim', ascending=False).iloc[0] # 记录配对行的原始索引 keep_indices.add(pos_row['index']) keep_indices.add(best_neg['index']) # 返回当前组保留的行 return df_group.loc[list(keep_indices)] # 对已经筛选过互为正负的df1按id分组处理 result = df1.groupby('id', group_keys=False).apply(filter_best_match).sort_index() print(result)
说明
如果需要替换为Jaccard相似度,仅需修改calc_str_similarity函数即可,参考实现:
def calc_str_similarity(a, b): set_a, set_b = set(a), set(b) return len(set_a & set_b) / len(set_a | set_b)
内容的提问来源于stack exchange,提问作者Unicorn07
相关产品推荐
相关产品推荐

