如何合并两个DataFrame并仅保留与df1行数一致的合并结果?
解决方案:合并DataFrame并保留指定次数的匹配行
当然可以实现这个需求!要做到基于指定列合并且结果行数与df1完全一致,核心是让df1的每一行仅对应df2中同组的第N个匹配项(按出现顺序计数)。下面是具体步骤和代码示例:
方法思路
我们可以通过给两个DataFrame的匹配组内添加序号,再基于「匹配列+序号」进行左连接,确保每个df1的行仅匹配df2中对应位置的行,从而严格控制结果行数与df1一致。
具体代码实现
import pandas as pd # 初始化你提供的数据集 df1 = pd.DataFrame( [[1, 2.1, 5, 0, 'a'], [7, 2.3, 5, 1, 'b'], [0, 2, 0, 1, 'c'], [9, 4, 4, 1, 'd']], columns=list('ABCDE') ) df2 = pd.DataFrame( [[3, 2, 5, 0, 1, 2], [3, 2.4, 5, 1, 9, 9], [9, 9, 5, 9, 4, 5], [0, 2, 5, 0, 1, 1], [1, 4, 4, 3, 8, 0]], columns=list('xBCyzw') ) # 步骤1:给df1的每个(B,C)组添加匹配序号 df1['match_idx'] = df1.groupby(['B', 'C']).cumcount() # 步骤2:给df2的每个(B,C)组添加匹配序号 df2['match_idx'] = df2.groupby(['B', 'C']).cumcount() # 步骤3:基于(B,C,match_idx)进行左连接,确保行数与df1一致 merged_df = pd.merge(df1, df2, on=['B', 'C', 'match_idx'], how='left') # 可选:删除临时的match_idx列 merged_df = merged_df.drop('match_idx', axis=1) print(merged_df)
代码解释
groupby(['B', 'C']).cumcount():对每个(B,C)组合的行进行组内计数,从0开始递增。这样df1和df2中同一(B,C)组的第1行、第2行都会有相同的match_idx。pd.merge(..., how='left'):以df1为基准进行左连接,只会保留df1中存在的行,且每个行仅匹配df2中同组同序号的行,完美保证结果行数与df1一致。- 如果df2中某个(B,C)组的行数少于df1中的对应组,那么多余的df1行在合并后对应的df2列会显示为
NaN,这是符合预期的(因为没有匹配项)。
输出结果示例
运行上述代码后,合并后的DataFrame如下:
A B C D E x y z w 0 1 2.1 5 0 a NaN NaN NaN NaN 1 7 2.3 5 1 b NaN NaN NaN NaN 2 0 2.0 0 1 c NaN NaN NaN NaN 3 9 4.0 4 1 d 1.0 3.0 8.0 0.0
可以看到,行数和df1完全一致(4行),只有df1中最后一行(B=4,C=4)在df2中有对应的匹配项,其他行因为df2没有同组同序号的匹配,所以df2的列显示为NaN。
扩展:如果需要保留指定次数的匹配(比如每组保留前2次)
如果你的需求是每组最多保留N次匹配,而不是严格和df1行数一致,可以在添加序号后过滤match_idx < N,再进行合并:
# 示例:每组最多保留2次匹配 max_matches = 2 df1_filtered = df1[df1.groupby(['B', 'C']).cumcount() < max_matches] df2_filtered = df2[df2.groupby(['B', 'C']).cumcount() < max_matches] merged_df = pd.merge(df1_filtered, df2_filtered, on=['B', 'C', 'match_idx'], how='left')
内容的提问来源于stack exchange,提问作者Raksha
相关产品推荐
相关产品推荐

