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

基于ID对比Pandas DataFrame筛选变更行的问题求助

基于ID列对比DataFrame并提取变更行的解决方案

先直接给你能解决问题的代码逻辑,再拆解说明:

核心步骤

  • 以ID列为键合并两个DataFrame,给两个表的列加后缀区分(_new对应df_merged,_old对应df_prod_filtered)
  • 指定需要检查变更的字段(比如成本、价格、预购状态)
  • 逐字段对比新旧值,生成“存在差异”的掩码
  • 筛选出至少有一个字段变更的行,提取df_merged的对应数据

完整代码示例

假设你的ID列名为'ID',需要检查变更的列是['商品成本', '价格', '预购状态'],替换成你实际的列名即可:

import pandas as pd
import numpy as np

# 1. 以ID列合并两个DataFrame,保留双方都有的ID(要保留所有ID用how='outer')
df_compare = pd.merge(
    df_merged, 
    df_prod_filtered, 
    on='ID', 
    suffixes=('_new', '_old'),
    how='inner'
)

# 2. 定义需要检查变更的字段列表
check_columns = ['商品成本', '价格', '预购状态']

# 3. 生成差异掩码:遍历每个检查列,对比新旧值是否不同
mask = pd.Series([False]*len(df_compare), index=df_compare.index)
for col in check_columns:
    # 处理数值类型的精度问题(比如float小数位)
    if df_compare[f'{col}_new'].dtype in ['float64', 'int64']:
        col_mask = ~np.isclose(df_compare[f'{col}_new'], df_compare[f'{col}_old'], atol=1e-6)
    else:
        # 字符串/布尔类型直接对比,同时处理空值差异
        col_mask = df_compare[f'{col}_new'] != df_compare[f'{col}_old']
        col_mask = col_mask | (df_compare[f'{col}_new'].isna() != df_compare[f'{col}_old'].isna())
    mask = mask | col_mask

# 4. 提取df_merged中存在变更的行
df_changes = df_merged[df_merged['ID'].isin(df_compare.loc[mask, 'ID'])]

# 输出结果
print("变更行数量:", len(df_changes))
df_changes.to_csv('shopify变更数据.csv', index=False)

为什么你之前的索引对比方法无效?

你用索引对比的mask方法,本质是假设两个DataFrame的索引顺序和ID完全对应,但实际场景中很可能出现:

  • 两个表的行顺序不一致
  • 存在ID仅在其中一个表出现的情况
  • 索引是自动生成的数字,和ID无关联
    所以必须基于ID列(唯一标识)做合并对比,而非依赖索引。

额外注意事项

  • 如果ID列存在重复值,需先处理重复(比如去重或聚合),否则合并后会出现重复行
  • 日期类型列需转成统一格式后再对比,避免格式差异导致误判
  • 若要查看具体变更字段,可新增列记录:
df_compare['变更字段'] = ''
for col in check_columns:
    change_mask = df_compare[f'{col}_new'] != df_compare[f'{col}_old']
    df_compare.loc[change_mask, '变更字段'] += col + ';'

内容的提问来源于stack exchange,提问作者Nazzeth

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 00:30:14