用 dtype 参数提前指定类型最省内存:跳过默认类型推断,避免 object 和 float64 等高内存类型;建议先用小样本分析分布,再依 min/max 选 int8/int16、用 float32 替 float64、字符串列转 category。

用 pandas.read_csv 的 dtype 参数提前指定类型最省内存
读取 CSV 时不做类型推断,直接告诉 pandas 每列该是什么类型,能跳过默认的 object 或宽泛数值类型(如 int64),从源头减少内存占用。pandas 默认对数字列常设为 float64,哪怕全是整数;对字符串列一律用 object,这两者都是内存黑洞。
实操建议:
- 先用小样本(
nrows=1000)调用pd.read_csv(..., nrows=1000)粗看各列分布,再用df.dtypes和df.memory_usage(deep=True)定位大列 - 对整数列:优先试
np.int8/np.int16,用df[col].min()和df[col].max()判断是否溢出 - 对浮点列:若精度允许,用
np.float32替代float64,内存减半 - 对字符串列:若取值有限(如状态码、分类标签),强制转
'category'类型,尤其当唯一值数
pd.to_numeric + downcast 是安全压缩数值列的核心手段
pd.to_numeric 不只是转类型,它的 downcast 参数能自动选最小可行类型,比手动判断更稳妥。它会先尝试 'integer',失败则退到 'signed'/'unsigned',再不行才用 'float',全程不报错(除非设 errors='raise')。
常见错误现象:直接对含空值(NaN)的列调 astype('int8') 会报 ValueError: Cannot convert non-finite values (NA or inf) to integer —— 这正是 pd.to_numeric 要解决的问题。
实操建议:
- 对疑似整数的列:用
pd.to_numeric(df[col], downcast='integer', errors='ignore'),errors='ignore'保证失败列原样保留 - 对浮点列:用
pd.to_numeric(df[col], downcast='float', errors='ignore'),它会选float32或float64 - 注意:
downcast对含NaN的整数列仍返回float32(因 pandas 整数类型不原生支持NaN),这是预期行为,不是 bug
字符串列转 'category' 前必须检查唯一值比例和内存增益
不是所有字符串列都适合转 category。当唯一值太多(比如用户 ID、时间戳字符串),转 category 反而增加内存——因为 pandas 需额外存一份索引数组 + 类别表。
使用场景:日志中的 status(只有 'OK'/'ERROR'/'PENDING')、电商中的 product_category(几百个固定类目)。
实操建议:
- 先算比例:
n_unique = df[col].nunique(); ratio = n_unique / len(df),ratio 是较安全的阈值 - 验证收益:执行
df[col].astype('category').memory_usage(deep=True)对比原列,只在结果更小时才赋值 - 避免链式操作陷阱:不要写
df[col] = df[col].astype('category')后立刻df[col].cat.codes—— 若原列是object且含NaN,cat.codes会把NaN编为-1,但显示仍是NaN,容易误判
用 df.select_dtypes 批量处理同类列,但需防类型冲突
一次性对所有数值列降级、所有字符串列转 category,看似高效,但实际容易踩坑:同一 select_dtypes 结果里可能混着不能统一处理的列(比如一列是日期字符串,一列是纯数字字符串)。
性能影响:批量操作本身不慢,但若某列转换失败(如把带字母的字符串强转 numeric),整个 apply 会中断或静默失效。
实操建议:
- 分组处理更稳:
num_cols = df.select_dtypes(include=['number']).columns→ 对每列单独pd.to_numeric(..., downcast=...) - 字符串列务必先过滤:
str_cols = df.select_dtypes(include=['object']).columns,再逐个用df[col].nunique() / len(df)判是否适合category - 永远用
deep=True校验:df.memory_usage(deep=True).sum()才是真实内存,忽略deep参数会严重低估object列开销
真正省内存的关键不在“全量扫描”,而在拒绝默认行为——pandas 的自动推断是为了兼容性,不是为了效率。每一处显式类型声明,都是对内存的精确控制。漏掉一个 NaN 处理或一个高基数字符串列,就可能让压缩效果打五折。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











