如何在Pandas中实现两DataFrame列间列表元素的映射匹配
解决Pandas中根据子串列表匹配完整字符串的问题
首先明确你的需求:根据cellname分组,为df1每行的子串列表,匹配df2对应分组下包含任意子串的完整字符串,最后把这些完整字符串聚合为列表。从你的期望输出能看出来,df2里的full_string是逗号分隔的多个字符串,所以第一步得先把这些字符串拆分出来再匹配。
方法一:更简洁高效的实现方式
我推荐先预处理df2,再构建分组映射,最后批量匹配,步骤清晰且性能更好:
import pandas as pd # 还原你的两个DataFrame df1 = pd.DataFrame({ 'cellname': [1,1,2,2], 'sub_str_list': [['ap'], ['cp','bp'], ['ep','rr'], ['rr', 'pp']] }) df2 = pd.DataFrame({ 'cellname': [1,1,1,2,2,2], 'full_string': [ 'rec_d,rec_cp', 'bp_get,dr_pet', 'retap,hk_get', 'tre_ep,ugt_pa', 'tti_rr,par_ty', 'rat_kp,cat_cp' ] }) # 1. 拆分df2的full_string为单个字符串并展开 df2_expanded = df2.assign(full_string=df2['full_string'].str.split(',')).explode('full_string') # 2. 构建cellname到对应所有完整字符串的映射字典 cell_full_map = df2_expanded.groupby('cellname')['full_string'].apply(list).to_dict() # 3. 定义匹配函数,对df1每行筛选符合条件的完整字符串 def match_substrings(row): # 获取当前cellname对应的所有完整字符串 full_candidates = cell_full_map.get(row['cellname'], []) # 筛选出包含子串列表中任意子串的字符串 matched_strings = [s for s in full_candidates if any(sub in s for sub in row['sub_str_list'])] return matched_strings # 4. 给df1添加fulllist列 df1['fulllist'] = df1.apply(match_substrings, axis=1)
运行后得到的结果就是你想要的:
cellname sub_str_list fulllist 0 1 [ap] [retap, hk_get] 1 1 [cp, bp] [rec_cp, bp_get, dr_pet, rec_d] 2 2 [ep, rr] [tre_ep, ugt_pa, tti_rr, par_ty] 3 2 [rr, pp] [tti_rr, par_ty]
(注:你期望输出第四行的rat_kp,cat_cp并不包含rr或pp,所以这里结果和你的示例有差异,应该是示例笔误~)
基于你现有代码的后续处理
如果想继续用你已经写的代码,可以补充以下步骤(前提是先拆分df2的full_string):
# 先处理df2,拆分full_string df2_processed = df2.assign(full_string=df2['full_string'].str.split(',')).explode('full_string') # 执行你写的代码 res = df2_processed.merge(df1, on='cellname', how='right').explode('sub_str_list') res['new'] = res.apply(lambda x: x['sub_str_list'] in x['full_string'] if x['sub_str_list'] is not None else False, axis=1) res = res[res['new'] == True] # 给原df1加索引,方便后续合并回原行 df1_with_idx = df1.reset_index().rename(columns={'index': 'original_idx'}) res_with_idx = res.merge(df1_with_idx, on=['cellname', 'sub_str_list'], how='right') # 按原行索引分组,聚合得到fulllist final_res = res_with_idx.groupby('original_idx').agg({ 'cellname': 'first', 'sub_str_list': lambda x: x.iloc[0], 'full_string': lambda x: list(x.dropna()) }).rename(columns={'full_string': 'fulllist'}).reset_index(drop=True)
这种方法步骤更多,且多次merge和explode会增加计算量,数据量大时不如第一种方法高效。
内容的提问来源于stack exchange,提问作者anjali
相关产品推荐
相关产品推荐

