Pandas 查找不匹配行:删除df2中与df1小时字段不匹配的多余行
问题根因
你之前使用isin方法达不到效果,核心错误是单独拿hour列做匹配依据:小时数值会按天循环重复,比如1月1日的1点和1月2日的1点在hour列上数值完全一致,用df2[df2["hour"].isin(df1["hour"])]做过滤时,只要某个小时值在df1里任何一天出现过,不管对应日期是不是匹配,都会把df2的这行保留,自然出现错位。
正确的匹配逻辑必须绑定对应的日期、电站等维度,用组合成的唯一标识做匹配,不能只看小时数值。
可行实现方案
方案1:复合键集合过滤(适合大表,运行效率高)
- 第一步:定义组成唯一匹配键的字段组,根据样例结构,能唯一标识一条记录的维度为:
plant_name、year、month、day、hour(如果业务场景下电站固定,可去掉plant_name字段,仅保留时间维度字段) - 第二步:将df1的所有合法匹配键提取为集合,集合的存在性判断时间复杂度为O(1),运行速度远快于逐行遍历
- 第三步:对df2逐行判断对应匹配键是否在df1的合法集合内,保留匹配成功的行
代码示例:
# 定义匹配字段列表 match_cols = ["plant_name", "year", "month", "day", "hour"] # 提取df1的所有合法匹配键,转为元组集合 valid_keys = set(df1[match_cols].itertuples(index=False, name=None)) # 过滤df2中匹配键在合法集合内的行,重置索引 df2_filtered = df2[ df2[match_cols].itertuples(index=False, name=None).isin(valid_keys) ].reset_index(drop=True) # 强制校验过滤后行数和df1完全一致 assert len(df2_filtered) == len(df1), "过滤后行数不匹配,请检查匹配字段是否覆盖所有唯一维度"
针对你提供的样例,df2中索引23的行(day=2, hour=0)生成的匹配键为("BIG HORN I", 2018, 1, 2, 0),该键不在df1的合法键集合中(df1中day=2的合法小时为1、2),会被自动过滤,最终结果和你给出的预期输出完全匹配。
方案2:内连接匹配(逻辑直观,不易出错)
如果不想手动处理键集合,可直接用pandas的内连接逻辑实现:内连接只会保留两个表在匹配字段上完全一致的行,和需求完全对齐。
match_cols = ["plant_name", "year", "month", "day", "hour"] # 内连接匹配,仅保留df1和df2共有的匹配键行 df2_filtered = df2.merge( df1[match_cols], # 仅从df1提取匹配需要的字段,减少计算量 on=match_cols, how="inner" ).reset_index(drop=True) # 校验行数 assert len(df2_filtered) == len(df1), "过滤后行数不匹配,请检查匹配字段是否覆盖所有唯一维度"
- 注意事项:
- 如果匹配字段中存在空值,需要提前做空值处理,因为pandas连接逻辑中空值无法实现匹配
- 如果连接后行数比df1多,说明当前选择的匹配字段组合不满足唯一性,需要补充能区分不同记录的维度字段
内容的提问来源于stack exchange,提问作者user2100039
相关产品推荐
相关产品推荐

