降低DataFrame内存占用:是否有比自定义dtype转换更高效的方法
现有实现的问题
你写的基础逻辑是对的,但存在几个影响性能和准确性的问题:
- 存在笔误:
has_decimal == 1是相等判断不是赋值,不过该变量后续未使用,不影响转换逻辑 any(df[col]%1!=0)是行级遍历,大数据量下速度极慢,换成pandas内置向量化判断(df[col] % 1 != 0).any()效率会高很多- 没有处理无符号整数场景:如果列最小值≥0,用uint类型能进一步压缩空间,比如0~255的范围用uint8只占1字节,比int8的存储范围大一倍
- 没有支持Nullable类型:pandas的Int8/Int16等支持空值的整数类型,遇到含NaN的整数列不会直接转成float,能进一步节省空间
- 未覆盖字符串、布尔、时间等非纯数值类型的压缩场景,这类场景的压缩空间通常比数值类型更大
更高效的压缩方案
1. 基于pandas内置方法的高性能压缩实现
不需要自己手写边界判断逻辑,用pd.to_numeric的downcast参数就能自动适配最优数值类型,底层是C实现的逻辑,比纯Python循环判断快3~10倍,还能自动处理无符号整数、Nullable类型的场景:
import pandas as pd from pandas.api.types import is_integer_dtype, is_float_dtype, is_object_dtype def compress_df_dtypes(df): for col in df.columns: if is_integer_dtype(df[col]): df[col] = pd.to_numeric(df[col], downcast='integer') elif is_float_dtype(df[col]): df[col] = pd.to_numeric(df[col], downcast='float') # 额外补充字符串列的压缩,基数低于50%的列转category压缩效果极佳 elif is_object_dtype(df[col]): unique_ratio = len(df[col].unique()) / len(df[col]) if unique_ratio < 0.5: df[col] = df[col].astype('category') return df
2. 读文件阶段提前压缩
如果是从csv等文件加载数据,不需要先读成默认类型再转,读入时就指定类型可以省掉中间的内存占用峰值:
- 先读10%的行做采样,推断最优类型,再按推断的类型读全量数据
- 时间列直接指定
parse_dates参数转成datetime64类型,不要存为字符串或者时间戳数值
3. 极端场景的定向优化
- 精度要求不高的浮点列可以直接强制转成float16,比自动压缩的空间占比再降一半
- 布尔值列显式转成boolean类型,单值仅占1字节,远小于默认的int类型
- 取值固定的离散列优先用category类型存储,最高可节省90%以上的内存
内容的提问来源于stack exchange,提问作者gtomer
相关产品推荐
相关产品推荐

