在Pandas中对齐两列字符串(递归合并直至匹配)
问题场景
现有如下Pandas DataFrame:
import pandas as pd df = pd.DataFrame(data={'col1': ["Sun", "Sea:", "SARS-COV-2", "Hong-Kong", "Fish", "NaN", "NaN", "NaN", "NaN", "NaN", "NaN", "NaN"], 'col2': ["Sun", "Sea", ":", "SARS", "-", "COV", "-", "2", 'Hong', '-', 'Kong', 'Fish'], 'col3': ["H", "Q", "S", "X", "Y", "Z", "L", "M", 'A', 'B', 'C', 'O']})
其中col1包含完整目标字符串和NaN值,col2是拆分后的字符串片段。需要合并col2的片段,使其与col1的非NaN值匹配,同时保留匹配时对应的第一个col3值,最终得到目标DataFrame:
df2 = pd.DataFrame(data={'col1': ["Sun","Sea:", "SARS-COV-2", "Hong-Kong", "Fish"], 'col2': ["Sun", "Sea:", "SARS-COV-2", "Hong-Kong", "Fish"], 'col3': ["H", "Q", "X", "A",'O']})
尝试嵌套循环实现但逻辑混乱,求可行方案。
解决方案
可以通过追踪合并进度+匹配目标字符串或者分组聚合的方式实现,两种方案都能避免混乱的嵌套循环:
方案一:逐行遍历合并
- 提取
col1中的目标字符串,过滤掉NaN值:targets = df[df['col1'] != 'NaN']['col1'].tolist() - 初始化合并缓存、结果列表和目标索引:
current_merge = "" result = [] target_idx = 0 - 遍历
col2片段,逐步拼接直到匹配当前目标:for seg, c3 in zip(df['col2'], df['col3']): current_merge += seg if current_merge == targets[target_idx]: # 找到匹配时,取该目标对应第一个片段的col3值 first_seg = targets[target_idx][0] if len(targets[target_idx]) == 1 else targets[target_idx].split(sep=None, maxsplit=1)[0] first_c3 = df.loc[df['col2'] == first_seg, 'col3'].iloc[0] result.append({ 'col1': targets[target_idx], 'col2': current_merge, 'col3': first_c3 }) # 重置缓存,切换到下一个目标 current_merge = "" target_idx += 1 if target_idx >= len(targets): break - 转换为目标DataFrame:
df2 = pd.DataFrame(result)
方案二:分组聚合(更高效)
利用Pandas的分组功能,通过目标位置标记分组,直接完成合并和取值:
- 标记分组:用
col1的非NaN值作为分组标记点,生成连续分组ID:df['group_id'] = df['col1'].ne('NaN').cumsum() - 分组聚合:合并每组的
col2片段,同时取每组第一个col3值,提取col1的目标字符串:df2 = df.groupby('group_id').agg( col1=('col1', lambda x: x[x != 'NaN'].iloc[0]), col2=('col2', ''.join), col3=('col3', 'first') ).reset_index(drop=True)
两种方案运行后得到的df2都完全符合需求,方案二更适合大数据量场景。
内容的提问来源于stack exchange,提问作者moon289
相关产品推荐
相关产品推荐

