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

为何value_counts与nunique拖慢4000个Excel文件的校验速度?

问题背景

处理约4000个单工作表Excel文件,每个表约200行10列。原本9项简单校验全程耗时约6分钟,新增check_10校验后总耗时骤增至20分钟。

check_10的校验目标:对每个固定capacity和chunks的id,验证两个规则:

  1. 唯一components数量不超过capacity
  2. components的总行数等于对应id的chunks值

示例代码及测试数据如下:

import pandas as pd

df = pd.DataFrame(
    {
        'id': ['381']*10 + ['382']*10,
        'components': ['A1']*4 + ['B1']*4 + ['A1']*2 + ['A1']*6 + ['C1']*4,
        'capacity': ['1']*10 + ['2']*10,
        'chunks': ['4']*10 + ['6']*10
    }
)

def check_10(df):
    cols = ['id', 'capacity', 'chunks']

    counts = df.groupby(cols, as_index=False)['components'].agg(total_components='value_counts')
    counts['unique_components'] = counts.groupby(cols)['components'].transform('nunique')

    # 原代码vc应为df,此处修正笔误
    result1 = counts['unique_components'].le(counts['capacity'].astype(int)).all()
    result2 = counts['total_components'].eq(df['chunks'].astype(int)).all()

    return result1 and result2

print(check_10(df))
# False

运行后生成的counts数据:

id capacity chunks components  total_components  unique_components
0  381        1      4         A1                 6                  2
1  381        1      4         B1                 4                  2
2  382        2      6         A1                 6                  2
3  382        2      6         C1                 4                  2
性能瓶颈原因

1. 重复分组遍历

原代码先通过groupby(cols).agg(total_components='value_counts')做第一次分组统计,随后又对结果再次groupby(cols)计算unique_components,相当于对同一份数据做了两次完整的分组遍历,4000个文件累加后,额外的遍历开销被放大。

2. value_counts导致数据膨胀

agg中使用value_counts会把每个分组内的不同components展开成单独行,比如一个分组有3种components,就会生成3行数据。这会让临时处理的数据量翻倍甚至更多,增加内存占用和后续计算的时间成本。

3. 重复类型转换

代码中多次对capacity和chunks执行astype(int)转换,每次转换都要遍历整列,4000次重复操作积累了可观的额外耗时。

4. 逻辑冗余(附带逻辑错误)

原代码中result2的判断逻辑有误:total_components是每个components的出现频次,而chunks是id对应的总数值,直接对比两者逻辑不成立;同时这段代码还错误引用了未定义的vc变量,即使修正为df['chunks'],也会再次遍历原数据,增加不必要的计算。

优化方案

将两次分组合并为一次,直接计算所需的聚合指标,减少遍历次数和临时数据量:

def check_10_optimized(df):
    # 提前转换列类型,避免重复操作
    df['capacity'] = df['capacity'].astype(int)
    df['chunks'] = df['chunks'].astype(int)
    
    # 一次分组完成所有需要的聚合计算
    agg_stats = df.groupby(['id', 'capacity', 'chunks'], as_index=False).agg(
        unique_components=('components', 'nunique'),
        total_components_count=('components', 'count')
    )
    
    # 验证两个规则
    rule1_pass = agg_stats['unique_components'].le(agg_stats['capacity']).all()
    rule2_pass = agg_stats['total_components_count'].eq(agg_stats['chunks']).all()
    
    return rule1_pass and rule2_pass

优化效果说明

  • 一次分组完成全部聚合计算,减少一半的数据遍历次数
  • 避免value_counts导致的数据行膨胀,临时数据量大幅降低
  • 提前转换列类型,消除重复转换的开销
  • 修正原逻辑中result2的错误,确保校验逻辑正确

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 12:40:20