如何基于列表中的匹配值实现两个DataFrame的左合并?
解决DataFrame列表值匹配的合并问题
问题背景
有如下两个DataFrame:
DF1:
time id 15-06 1 16-06 3 17-06 5 18-06 7
DF2:
result idx 'asd' [18,3] 'qwe' [20,5] 'zxc' [7] 'ty' [987,9] 'qwe' [1000]
期望输出:
time id result idx 15-06 1 NaN NaN 16-06 3 'asd' [18,3] 17-06 5 'qwe' [20,5] 18-06 7 'zxc' [7]
尝试左合并时无法匹配列表中的值:
df1.merge(df2, how="left", left_on = "id", right_on="idx")
尝试赋值数据时出现表长度不一致问题:
df3 = df.assign(id=[[s.get(y) for y in x if y in s] for x in df2['idx']])
解决方案
核心是建立DF1的id与DF2中idx列表元素的对应关系,再完成合并。
方法一:拆分列表列后构建映射(高效)
适合数据量较大的场景,通过拆分DF2的列表列生成映射表,再合并:
import pandas as pd # 构造示例数据 df1 = pd.DataFrame({'time': ['15-06', '16-06', '17-06', '18-06'], 'id': [1, 3, 5, 7]}) df2 = pd.DataFrame( {'result': ["'asd'", "'qwe'", "'zxc'", "'ty'", "'qwe'"], 'idx': [[18, 3], [20, 5], [7], [987, 9], [1000]]} ) # 拆分DF2的idx列表,生成每个元素对应行 df2_exploded = df2.explode('idx', ignore_index=True) # 构建id到result和原idx列表的映射(取第一个匹配项) mapping = df2_exploded.groupby('idx').agg( {'result': 'first', 'idx': lambda x: df2.loc[x.index[0], 'idx']} ) # 左合并df1和映射表 result = df1.merge(mapping, left_on='id', right_index=True, how='left') # 调整列名与期望输出一致 result.rename(columns={'idx_y': 'idx'}, inplace=True) print(result)
方法二:逐行匹配(直观)
适合小数据量场景,直接遍历DF1的每行,在DF2中查找包含对应id的记录:
import pandas as pd # 构造示例数据同上 df1 = pd.DataFrame({'time': ['15-06', '16-06', '17-06', '18-06'], 'id': [1, 3, 5, 7]}) df2 = pd.DataFrame( {'result': ["'asd'", "'qwe'", "'zxc'", "'ty'", "'qwe'"], 'idx': [[18, 3], [20, 5], [7], [987, 9], [1000]]} ) def get_matching_record(row): # 筛选DF2中idx列表包含当前id的行 match_row = df2[df2['idx'].apply(lambda lst: row['id'] in lst)] if not match_row.empty: return pd.Series([match_row['result'].iloc[0], match_row['idx'].iloc[0]]) return pd.Series([pd.NA, pd.NA]) # 为DF1添加匹配的result和idx列 df1[['result', 'idx']] = df1.apply(get_matching_record, axis=1) print(df1)
两种方法均可得到符合期望的输出。
内容的提问来源于stack exchange,提问作者Tmiskiewicz
相关产品推荐
相关产品推荐

