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

如何用Pandas对比DataFrame识别已完成与待完成实验任务?

Pandas合并操作异常问题排查

问题背景

我有两个DataFrame:

  • df_ref(从YAML生成):包含所有计划运行的实验配置
  • df_data(从CSV读取):记录已完成的实验

需求:

  1. 返回已完成和待完成的实验任务列表(字典格式)
  2. YAML的列是CSV列的严格子集
  3. 可移除对比中无关的列

现有代码

def get_incomplete_configs(full_config, project, user='',  drop_cols=[]):
    
    # load in csv (downloaded from wandb)
    configsrun_df = pd.read_csv('completed_runs.csv') 

    # proposed config dataframe
    full_config = pd.DataFrame(full_config).drop_duplicates()

    # which attributes do we care about
    merge_on = list(set(full_config.columns.values) - set(drop_cols))

    # pick the relevant ones
    configsrun_df = configsrun_df[merge_on].dropna() 
    full_config = full_config[merge_on].dropna()
    
    # type matching  
    mismatches = [(i, configsrun_df[col].dtype, full_config[col].dtype) for i, col in enumerate(merge_on) if configsrun_df[col].dtype != full_config[col].dtype]
    if len(mismatches):
        for m in mismatches: 
            if (m[1]=='int64') or (m[2]=='int64'):  
                configsrun_df[merge_on[m[0]]] = configsrun_df[merge_on[m[0]]].astype(int)
                full_config[merge_on[m[0]]] = full_config[merge_on[m[0]]].astype(int)
            else:
                raise Exception

    # merging operation which should work
    completed_runs = pd.merge(full_config, configsrun_df, indicator=True, how='outer').query('_merge=="left_only"').drop('_merge', axis=1).drop_duplicates()
  
    # convert to list of dicts
    completed_runs = completed_runs.T.to_dict().values()
    print('this job is {}% complete'.format(round(len(completed_runs)/len(full_config),2)))
    
    # return 
    return completed_runs

核心疑问

当前merge操作返回结果异常,数据量不匹配,对合并操作的理解哪里有问题?


问题分析与修正

1. 合并结果含义完全搞反

你当前代码中:

completed_runs = pd.merge(...).query('_merge=="left_only"')

outer join后的_merge字段含义:

  • left_only:仅存在于full_config(计划任务)中的记录 → 待完成任务
  • both:同时存在于计划和已完成列表中的记录 → 已完成任务
  • right_only:仅存在于已完成列表中的记录 → 计划外的额外任务

你把left_only的结果命名为completed_runs,完全颠倒了含义,这是数据量不匹配的核心原因。

2. 列顺序丢失导致隐性问题

用集合操作生成merge_on会打乱原始列顺序:

merge_on = list(set(full_config.columns.values) - set(drop_cols))

虽然merge不依赖列顺序,但后续类型转换、数据校验可能出现隐性错误,建议改为列表推导式保持顺序:

merge_on = [col for col in full_config.columns if col not in drop_cols]

3. 类型转换逻辑过于激进

原代码仅处理int64类型不匹配的情况,其他直接抛异常,无法处理常见的类型兼容问题(比如CSV中是float但实际是整数、字符串含空格等)。建议采用更通用的转换逻辑:优先转为数值类型,失败则转为字符串并去除首尾空格。

4. 提前dropna丢失有效记录

merge前对两个DataFrame执行dropna(),会直接丢失存在缺失值的计划任务或已完成任务,应该先处理类型匹配,再根据业务需求决定是否过滤缺失值。


修正后的代码

def get_task_status(full_config, project, user='', drop_cols=[]):
    # 加载已完成任务CSV
    configsrun_df = pd.read_csv('completed_runs.csv') 
    # 转换计划任务为DataFrame并去重
    full_config = pd.DataFrame(full_config).drop_duplicates()

    # 确定用于匹配的列(保持原始顺序)
    merge_on = [col for col in full_config.columns if col not in drop_cols]

    # 筛选相关列
    configsrun_df = configsrun_df[merge_on]
    full_config = full_config[merge_on]

    # 类型匹配优化:优先统一为数值类型,失败则转为字符串
    for col in merge_on:
        try:
            # 尝试转为整数(自动处理CSV中的float整数)
            configsrun_df[col] = pd.to_numeric(configsrun_df[col], downcast='integer')
            full_config[col] = pd.to_numeric(full_config[col], downcast='integer')
        except (ValueError, TypeError):
            # 转为字符串并去除首尾空格,避免格式差异导致匹配失败
            configsrun_df[col] = configsrun_df[col].astype(str).str.strip()
            full_config[col] = full_config[col].astype(str).str.strip()

    # 执行外连接,标记匹配状态
    merged = pd.merge(full_config, configsrun_df, on=merge_on, indicator=True, how='outer')

    # 分离待完成、已完成任务
    incomplete_runs = merged[merged['_merge'] == 'left_only'].drop('_merge', axis=1).drop_duplicates()
    completed_runs = merged[merged['_merge'] == 'both'].drop('_merge', axis=1).drop_duplicates()

    # 转换为字典列表(更简洁的方式)
    incomplete_list = incomplete_runs.to_dict('records')
    completed_list = completed_runs.to_dict('records')

    # 计算并打印完成率
    completion_rate = round(len(completed_list) / len(full_config) * 100, 2)
    print(f'任务完成率:{completion_rate}%')

    # 返回已完成和待完成任务列表
    return {'completed': completed_list, 'incomplete': incomplete_list}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 14:15:37