自学教程 学编程从这里开始

Pandas 处理大文件

承接《Pandas 抽样与随机数据》,本篇讲解 Pandas 处理超大 CSV/Excel 等文件的方案:分块读取、分批迭代、只读取指定列、数据类型压缩、Dtype 优化、内存查看、chunksize、skiprows、低内存模式、写入分块、大文件避坑,适合几十MB~数GB级数据,保持系列教程统一风格。
前置导入

import pandas as pd
import numpy as np

一、问题背景

直接 pd.read_csv("big.csv") 一次性载入,文件超过内存就会:

  • 内存爆满、程序被系统杀死
  • 交换分区大量占用,速度极慢

核心思路:不要一次性全部读到内存,分批加载 + 减少加载内容 + 优化数据类型

二、chunksize 分块迭代读取(最核心)

chunksize 指定每一块读取多少行,返回迭代器,循环逐块处理,内存只保留当前块。

# 每次读取 10000 行
chunk_iter = pd.read_csv("big.csv", chunksize=10000)

for chunk in chunk_iter:
    # 对每一块做清洗、过滤、统计、写入
    res = chunk[chunk["sales"] > 1000]
    # 追加写入结果
    res.to_csv("filter_result.csv", mode="a", header=False, index=False)

注意:第一次写入需要 header=True,后续追加 header=False,避免重复写表头。

封装表头判断版本:

first = True
for chunk in pd.read_csv("big.csv", chunksize=10000):
    chunk_filter = chunk[chunk["amount"] > 0]
    chunk_filter.to_csv("out.csv", mode="a", header=first, index=False)
    first = False

三、只读取需要的列 usecols

不需要的列直接不加载,大幅减少内存占用

# 只加载 id、sales、date 三列
df = pd.read_csv("big.csv", usecols=["id", "sales", "date"])

也可以传索引列表:

df = pd.read_csv("big.csv", usecols=[0,2,5])

四、跳过行、限制读取行数

  • nrows:只读取前N行,用来快速预览、测试脚本
  • skiprows:跳过前面若干行
# 只读取前5000行,调试用
df = pd.read_csv("big.csv", nrows=5000)

# 跳过前2行
df = pd.read_csv("big.csv", skiprows=2)

skiprows 也可以传函数,跳过指定行号。

五、dtype 类型压缩,降低内存(非常有效)

默认自动识别类型经常浪费内存:int64、float64 占空间很大。
在读取时直接指定 dtype,缩小存储空间:

dtype_map = {
    "id": "int32",
    "sales": "float32",
    "region": "category"
}
df = pd.read_csv("big.csv", dtype=dtype_map)
  • category:适合基数少、重复多的字符串(地区、分类、标签),内存压缩效果极强
  • 数字优先用 int8 / int16 / int32、float32,在取值范围允许下使用

⚠️ 注意:数值超出范围会报错,要先确认值域。

六、parse_dates 按需解析时间

时间解析开销很大,不需要就不要开启;需要则指定列:

df = pd.read_csv("big.csv", parse_dates=["order_time"])

如果格式固定,搭配 format 加速解析:

df = pd.read_csv("big.csv", parse_dates=["order_time"], format="%Y-%m-%d %H:%M:%S")

七、low_memory 参数警告

经常遇到警告:DtypeWarning: Columns have mixed types.
原因:同一列前面行是数字,后面行是字符串,Pandas自动推断类型混乱。
两种方案:

  1. 提前指定 dtype(推荐)
  2. low_memory=False 关闭分块推断(治标不治本)
df = pd.read_csv("big.csv", low_memory=False)

八、查看内存占用 memory_usage

# 每一列内存,单位字节
df.memory_usage(deep=True)
# 汇总
print(df.memory_usage(deep=True).sum() / 1024 / 1024, "MB")

deep=True 对 object、category 字符串列统计更准确。

九、大文件写入:分块写入

不要把所有结果攒到内存再写,边处理边输出。
前面 chunksize 示例就是标准写法。
如果是输出 Excel:xlsx 不适合超大文件;大输出优先 csv / parquet。

重点:Excel 本身不适合千万行级别数据,尽量避免。

十、Parquet 格式替代 CSV(高性能二进制格式)

CSV 是文本,读写慢、占内存;Parquet 列式存储,自带压缩、类型保存,是大数据首选。

# 写入
df.to_parquet("data.parquet", compression="snappy")
# 读取,支持指定列
df = pd.read_parquet("data.parquet", columns=["id","sales"])

Parquet 天然支持:

  • 按列读取、分区读取
  • 压缩、类型持久化
  • 比csv快很多,体积小很多

Feather 也是类似列式格式,适合 Pandas 内部交换。

十一、大Excel文件处理

read_excel 底层 openpyxl / xlrd 性能弱,不适合超大Excel。

  • 小几万行:正常 read_excel
  • 几十万行以上:优先导出为csv
  • 必须读大xlsx:使用 openpyxl + 迭代,或者 chunk(pandas excel chunk支持有限)
# 不推荐超大数据用excel
df = pd.read_excel("big.xlsx", sheet_name="sales")

十二、进阶:Dask(替代Pandas,超大数据)

当文件大到单块都难以处理,直接换 Dask DataFrame,API 和 Pandas 几乎一致,自动分块并行:

import dask.dataframe as dd
dask_df = dd.read_csv("big.csv", dtype=dtype_map)
res = dask_df[dask_df["sales"]>1000].compute()

compute() 才会触发计算,把结果拉回Pandas。

十三、常用场景模板

模板1:分块统计汇总(求和、计数)

total_sales = 0
cnt = 0
for chunk in pd.read_csv("big.csv", chunksize=10000):
    total_sales += chunk["sales"].sum()
    cnt += len(chunk)
print("总销售额:", total_sales)
print("总行数:", cnt)

模板2:分块过滤输出新文件

first_flag = True
for chunk in pd.read_csv("big.csv", chunksize=20000, usecols=["id","sales","region"]):
    out = chunk[chunk["sales"] >= 500]
    out.to_csv("filter_out.csv", mode="a", header=first_flag, index=False)
    first_flag = False

十四、高频坑清单

  1. chunksize 不是越小越好,太小IO频繁,速度变慢;一般 1w~10w 行,根据内存调试
  2. 分块循环里用 pd.concat 不断追加到列表外面,越攒越大,失去分块意义
  3. category 用于基数很大的字段(比如id、订单号),反而更耗内存
  4. 读取时不指定dtype,默认int64/float64,内存翻倍
  5. 表头重复:追加写入忘记控制header,结果文件多行表头
  6. 混合类型列不处理,low_memory警告,数据读错
  7. 超大Excel幻想用pandas直接读取,极易卡死
  8. 分块join/merge:跨块关联很难,分块适合单文件过滤、统计,关联尽量用Parquet+Dask

十五、速查表

需求方案
文件太大内存不够read_csv(chunksize=N) 迭代
只需要部分字段usecols 指定列
减少内存占用dtype + category
快速预览测试nrows
高性能存储格式parquet(snappy压缩)
千万行级Excel优先转csv,不推荐pandas直接读
超大数据、并行Dask DataFrame
查看内存消耗memory_usage(deep=True)
标签:

0 条笔记