You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.26 12:24:07