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

遍历二维DataFrame所有单元格速度极慢,问题出在哪?

问题:Pivot后DataFrame逐单元格遍历赋值性能极差

我从CSV读取DataFrame,按两列做pivot后尝试遍历每个单元格处理。实际代码包含复杂数值逻辑,但速度慢到离谱,于是写了个仅读取再赋值回原单元格的测试代码,排除处理逻辑的影响,聚焦访问/赋值的低效:

import pandas as pd
from tqdm import tqdm


def test_speed():
    df = pd.read_csv('https://media.githubusercontent.com/media/datablist/sample-csv-files/main/files/customers/customers-100.csv')
    df = pd.pivot(df, index='Index', columns='Country')

    original = df.copy()

    inputs = df.columns.values

    # process each row at a time
    for row_index in tqdm(range(df.shape[0])): 
        row_data = df.iloc[row_index]  # get the row

        for input_idx in range(len(inputs)):
            # for each column label, get the value
            val = row_data[inputs[input_idx]]  

            # just assign them back to that cell 
            df.iloc[row_index, input_idx] = val

    print(f'Are they equal? {original.equals(df)}')


if __name__ == '__main__':
    test_speed()

运行结果显示每秒仅处理22行:

100%|██████████| 100/100 [00:04<00:00, 22.63it/s]
Are they equal? True

对比之下,用DictReader遍历CSV每秒能处理约5000行;如果在pivot前处理,速度能到每秒1600行。怀疑赋值时会重建索引,但我并没有修改pivot用的行/列,想找个既能保留pivot结构又能提升性能的方法。


解决方案:避免逐单元格操作,利用Pandas向量化特性

核心原因

Pandas的iloc逐单元格赋值会触发多次内部索引校验、数据结构更新,尤其是pivot后的多级索引DataFrame,每次赋值的额外开销会被大幅放大,导致整体速度暴跌。

优化方案1:转NumPy数组处理后转回

将pivot后的DataFrame数据转换为NumPy数组,在数组层面完成逐元素操作(NumPy的内存布局更高效,访问/赋值开销远低于Pandas单元格操作),处理完成后再重新封装回原DataFrame结构:

import pandas as pd
from tqdm import tqdm

def test_speed_optimized():
    df = pd.read_csv('https://media.githubusercontent.com/media/datablist/sample-csv-files/main/files/customers/customers-100.csv')
    df = pd.pivot(df, index='Index', columns='Country')
    original = df.copy()

    # 转换为NumPy数组
    arr = df.to_numpy()

    # 遍历数组处理(此处模拟原逻辑,实际替换为你的复杂数值处理)
    for row_idx in tqdm(range(arr.shape[0])):
        for col_idx in range(arr.shape[1]):
            val = arr[row_idx, col_idx]
            arr[row_idx, col_idx] = val

    # 将处理后的数组转回原DataFrame结构
    df_processed = pd.DataFrame(arr, index=df.index, columns=df.columns)

    print(f'Are they equal? {original.equals(df_processed)}')

if __name__ == '__main__':
    test_speed_optimized()

该方案可将速度提升至每秒数千行,是保留pivot结构前提下的高效选择。

优化方案2:使用Pandas向量化API替代遍历

如果你的复杂数值逻辑可以用Pandas向量化函数实现(比如applymap、transform,或结合NumPy向量化操作),完全不需要手动遍历:

# 示例:用applymap处理每个单元格,替换lambda为你的自定义处理函数
df_processed = df.applymap(lambda x: x)

向量化操作是Pandas的最优实践,内部采用C级循环,性能比Python级遍历高几个数量级。

优化方案3:用itertuples减少行访问开销(次选)

如果必须逐行处理,itertuples比iloc取行的效率更高——它返回元组而非Series,减少了对象创建的开销。注意建议先收集所有处理结果,最后一次性赋值,避免逐单元格修改:

results = []
for row in tqdm(df.itertuples(index=True), total=df.shape[0]):
    row_vals = []
    # 多级列名需要拼接为属性名访问
    for col in df.columns:
        col_attr = f"{col[0]}_{col[1]}"
        val = getattr(row, col_attr)
        # 此处替换为你的处理逻辑
        row_vals.append(val)
    results.append(row_vals)

# 一次性赋值回DataFrame
df.loc[:] = results

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 04:02:36