如何基于指定条件实现DataFrame数据的一对一匹配
一对一匹配DataFrame数据的解决方案
问题背景
给定如下DataFrame:
import pandas as pd df = pd.DataFrame(columns=['ID', 'job', 'eligible', "date"]) df['ID'] = ['1', '2', '3', '4', '5', '6', '7', '8'] df['job'] = ['waitress', 'doctor', 'benevolent', 'nurse', 'hairstylist', 'banker', 'waitress', 'waitress'] df['eligible'] = ['No', 'Yes', 'No', 'Yes', 'No', 'No', 'No', 'No'] df['date'] = ['1.1.2016', '31.12.2015', '1.1.2016', '31.12.2015', '1.1.2016', '31.12.2015', '1.1.2015', '1.1.2015'] df["date"] = pd.to_datetime(df["date"])
需要按以下规则完成一对一唯一匹配:
- 匹配条件:
job和eligible字段值完全相同,且date年份为2015与2016互配 - 若某条数据有多个匹配项,随机选择一个
- 核心约束:每条数据只能被匹配一次,未匹配数据无需处理
期望输出格式示例:
# 随机匹配结果可能略有差异 df_paired = pd.DataFrame({ 'ID': ['1'], 'job': ['waitress'], 'eligible': ['No'], 'paired_ID': ['8'] })
解决方案
通过分组筛选+随机打乱+已匹配标记的方式实现唯一匹配,代码如下:
import pandas as pd # 预处理:提取年份字段 df['year'] = df['date'].dt.year # 存储匹配结果与已匹配ID paired_data = [] matched_ids = set() # 按job+eligible分组处理,确保同类型内匹配 for (job_val, eligible_val), group in df.groupby(['job', 'eligible']): # 拆分2015和2016年的子集 df_2015 = group[group['year'] == 2015].copy() df_2016 = group[group['year'] == 2016].copy() # 随机打乱顺序,实现随机匹配(可移除random_state让每次结果不同) df_2015 = df_2015.sample(frac=1, random_state=42).reset_index(drop=True) df_2016 = df_2016.sample(frac=1, random_state=42).reset_index(drop=True) # 取两组较小长度进行一对一匹配 match_num = min(len(df_2015), len(df_2016)) for i in range(match_num): id_16 = df_2016.loc[i, 'ID'] id_15 = df_2015.loc[i, 'ID'] # 检查是否未被匹配,避免重复使用 if id_16 not in matched_ids and id_15 not in matched_ids: paired_data.append({ 'ID': id_16, 'job': job_val, 'eligible': eligible_val, 'paired_ID': id_15 }) matched_ids.update([id_16, id_15]) # 生成结果DataFrame df_paired = pd.DataFrame(paired_data) print(df_paired)
代码说明
- 提取年份:从
date字段中提取年份,简化分组筛选操作 - 分组处理:按
job+eligible分组,确保仅在同属性数据中匹配 - 随机打乱:对2015、2016年的子集随机排序,满足随机匹配需求
- 唯一匹配:用
matched_ids集合跟踪已匹配的ID,确保每条数据仅被使用一次 - 长度适配:取两组数据的最小长度进行匹配,避免出现一对多的无效匹配
运行后会得到符合要求的唯一匹配结果,移除random_state参数可让每次运行的配对结果随机变化。
内容的提问来源于stack exchange,提问作者anacondah88
相关产品推荐
相关产品推荐

