Pandas读取大CSV太慢的6个实测提速技巧

 更新时间:2026年10月01日 06:38:43   作者:小小张说故事  
一个 2GB 的 CSV,pd.read_csv() 卡了 8 分钟,内存还飙到 12GB,这是很多人第一次处理稍微大一点的数据时都会遇到的场面,问题基本不在 pandas 慢,而在默认参数太保守,下面 6 个技巧,按改动成本从低到高排列,实测能把耗时和内存同时砍掉一大截,需要的朋友可以参考下

引言

一个 2GB 的 CSV,pd.read_csv() 卡了 8 分钟,内存还飙到 12GB——这是很多人第一次处理"稍微大一点"的数据时都会遇到的场面。

问题基本不在 pandas 慢,而在默认参数太保守:它会把每一列都当成可能的混合类型,先全部读进来,再逐个推断。下面 6 个技巧,按改动成本从低到高排列,实测能把耗时和内存同时砍掉一大截。

1. 先指定 dtype,别让 pandas 猜

这是收益最大、改动最小的一条。

# 慢:让 pandas 推断 30 列的类型
df = pd.read_csv("big.csv")

# 快:直接告诉它每列是什么
df = pd.read_csv("big.csv", dtype={
    "user_id": "int64",
    "city":    "category",
    "amount":  "float32",
})

两个关键点:

  • 字符串列用 category:重复值多的列(城市、状态、品类)转 category 后,内存能从几百 MB 降到几十 MB;
  • 浮点数能用 float32 就别用 float64:精度够用的场景直接省一半内存。

不知道有哪些列?先读一小段探一下:

cols = pd.read_csv("big.csv", nrows=5).columns
sample = pd.read_csv("big.csv", nrows=10000)
print(sample.dtypes)
print(sample.memory_usage(deep=True).sum() / 1024**2, "MB")

2. 只读需要的列(usecols)

如果文件有 50 列而你只用 6 列,usecols 是直接绕过剩下 44 列的解析成本:

df = pd.read_csv("big.csv", usecols=["user_id", "amount", "city", "date"])

用列的位置也比用名字快一点点(省掉一次名字匹配):

df = pd.read_csv("big.csv", usecols=[0, 3, 7, 11])

3. 日期别在读取时解析,读进来再转

parse_dates 很方便,但它是逐值调用日期解析器的,在大文件上极其昂贵。

# 慢
df = pd.read_csv("big.csv", parse_dates=["date"])

# 快:先当字符串读进来,再一次性转
df = pd.read_csv("big.csv")
df["date"] = pd.to_datetime(df["date"], format="%Y-%m-%d")

务必带上 format。不指定格式时 pandas 会逐值猜测,指定了才能走向量化的快路径。

4. 分块处理:chunksize

内存不够时的标准解法。读成分块迭代器,边算边丢:

total = 0.0
for chunk in pd.read_csv("big.csv", chunksize=200_000,
                         usecols=["amount", "city"],
                         dtype={"amount": "float32", "city": "category"}):
    total += chunk.groupby("city", observed=True)["amount"].sum().sum()

print(total)

注意两点:

  • chunksize 不是越小越好,太小会放大 Python 循环开销,20 万~50 万行比较合适;
  • groupby 加 observed=True,否则 category 类型会生成全组合的笛卡尔积行,白占内存。

5. 换引擎:pyarrow 比默认 C 引擎更快

pandas 2.x 起支持 engine="pyarrow",多线程解析,在多核机器上提速明显:

df = pd.read_csv("big.csv", engine="pyarrow", dtype_backend="pyarrow")

没装就先装:

pip install pyarrow

dtype_backend="pyarrow" 会用 Arrow 的原生类型(string、int32 等),内存占用通常再降一档。缺点是部分老 API 不兼容,导入后如果要和 scikit-learn 打交道,建议再 .convert_dtypes() 或直接 .to_numpy()。

6. 终极方案:先把 CSV 转成 Parquet

如果你要反复读同一个文件,那就别每次都解析 CSV 了。一次转换,后续读取快 5~10 倍:

# 一次性转换
df = pd.read_csv("big.csv", dtype={...})
df.to_parquet("big.parquet", compression="snappy")

# 后续读取(列式存储,只加载需要的列)
df = pd.read_parquet("big.parquet", columns=["user_id", "amount"])

Parquet 的三个好处:

  • 列式存储:columns= 能真正跳过不用的列,不用解析整个文件;
  • 自带 schema:不用每次推断 dtype;
  • 体积小:snappy 压缩后通常只有原 CSV 的 20%~30%。

附:一个通用提速模板

把上面几条打包成一个函数,日常直接复用:

import pandas as pd

def read_fast(path, usecols=None, dtypes=None, chunksize=None):
    kwargs = dict(
        usecols=usecols,
        dtype=dtypes,
        engine="pyarrow",
    )
    if chunksize:
        return pd.read_csv(path, chunksize=chunksize, **kwargs)
    return pd.read_csv(path, **kwargs)

# 用法
df = read_fast(
    "big.csv",
    usecols=["user_id", "amount", "city", "date"],
    dtypes={"user_id": "int64", "amount": "float32", "city": "category"},
)
df["date"] = pd.to_datetime(df["date"], format="%Y-%m-%d")

排错清单

  • 报 MemoryError:先加 usecols + category,再上 chunksize,最后考虑换 Parquet;
  • dtype 指定后报类型冲突:说明该列里有脏值(比如数字列混进了 "NULL" 字符串),加 na_values=["NULL", "", "NA"];
  • 转换 Parquet 后读取更慢:文件太小(< 50MB)时 Parquet 的列式开销反而不划算,CSV 直接读更快;
  • chunksize 循环里 groupby 结果不对:分块会把同一 key 切到不同块,需要把每块的结果再 concat 后聚合一次,别直接对每块 sum() 后相加。

小结

优先级排序:usecols + dtype(零成本,收益最大)→ 延后日期解析 → 换 pyarrow 引擎 → 分块 → 转 Parquet。

大多数"pandas 太慢"的场景,光做前两条就能解决,根本用不到换工具。真正需要上 Dask / Polars 的,是那种内存死活放不下的单机极限场景——在那之前,先把默认参数调明白。

你处理过最大的 CSV 是多少 G?用的什么办法,评论区交流一下。

到此这篇关于Pandas读取大CSV太慢的6个实测提速技巧的文章就介绍到这了,更多相关Pandas读取大CSV太慢提速技巧内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • python+pytest自动化测试函数测试类测试方法的封装

    python+pytest自动化测试函数测试类测试方法的封装

    这篇文章主要介绍了python+pytest自动化测试函数测试类测试方法的封装,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-06-06
  • python制作罗盘时钟效果

    python制作罗盘时钟效果

    这篇文章主要介绍了python制作罗盘时钟效果,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-04-04
  • Python中asyncore异步模块的用法及实现httpclient的实例

    Python中asyncore异步模块的用法及实现httpclient的实例

    asyncore即是一个异步的socket封装,特别是dispatcher类中包含了很多异步调用的socket操作方法,非常犀利,下面我们就来讲解Python中asyncore异步模块的用法及实现httpclient的实例
    2016-06-06
  • Python内存泄漏从200MB涨到8GB的排查与解决方法

    Python内存泄漏从200MB涨到8GB的排查与解决方法

    你的Flask应用是否也遭遇过内存狂飙?本文从一次OOM Killer杀死服务的真实案例出发,手把手教你用tracemalloc和objgraph定位Python内存泄漏,需要的朋友可以参考下
    2026-08-08
  • python自动化实现的简单使用

    python自动化实现的简单使用

    本文主要介绍了python自动化实现的简单使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • python em算法的实现

    python em算法的实现

    这篇文章主要介绍了python em算法的实现,帮助大家更好的理解机器学习,感兴趣的朋友可以了解下
    2020-10-10
  • Python性能调优的十个小技巧总结

    Python性能调优的十个小技巧总结

    大家好,今天这篇文章关于Python性能调优的10个小技巧,每天花5-10分钟阅读我的文章,对你技术提升一定会有帮助。喜欢记得收藏以防迷路
    2021-11-11
  • Python中连接不同数据库的方法总结

    Python中连接不同数据库的方法总结

    在数据驱动的现代应用开发中,Python凭借其丰富的库和强大的生态系统,成为连接各种数据库的理想编程语言,下面我们就来看看如何使用Python实现连接常用的几个数据库吧
    2025-02-02
  • 在Python中操作字典之clear()方法的使用

    在Python中操作字典之clear()方法的使用

    这篇文章主要介绍了在Python中操作字典之clear()方法的使用,是Python入门的基础知识,需要的朋友可以参考下
    2015-05-05
  • 一文完全掌握Python三大语句之顺序、条件与循环

    一文完全掌握Python三大语句之顺序、条件与循环

    Python是一种简单而强大的编程语言,它提供了多种结构和语句,使得程序编写变得更加灵活和高效,这篇文章主要介绍了Python三大语句之顺序、条件与循环的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-08-08

最新评论