PandasPandas 内存优化:从字典映射到分类数据类型的实战

为什么分类类型能省内存?

在 Pandas 中,object 类型(字符串)每元素存储的是 Python 对象的引用,占用 8 字节指针 + 字符串对象本身,而 category 类型内部使用整数编码 + 一个唯一的映射表。当一列有大量重复值时,用整数替代字符串能大幅压缩内存。比如性别列只有 'M'/'F' 两种值,100 万行 object 列约占用 80 MB,而 category 列仅约 8 MB(整数编码 8 字节 + 映射表)------节省 90%。

最小可运行示例:从字符串到分类

下面代码演示核心转换过程。先创建一个含重复字符串的 DataFrame,然后使用 astype('category') 转换,并对比内存占用。

复制代码
import pandas as pd
import numpy as np

# 模拟 10 万行重复类别数据
n = 100000
categories = ['apple', 'banana', 'orange', 'grape']
df = pd.DataFrame({'fruit': np.random.choice(categories, n)})

print('object 内存:', df['fruit'].memory_usage(deep=True))
# 输出约 8000000 字节

df['fruit_cat'] = df['fruit'].astype('category')
print('category 内存:', df['fruit_cat'].memory_usage(deep=True))
# 输出约 4000 字节(不含映射表)

# 查看分类编码
print(df['fruit_cat'].cat.codes.head())
print(df['fruit_cat'].cat.categories)

注意:memory_usage(deep=True) 会计算对象内部引用的真实内存,而 category 的映射表存储在 .cat.categories 中,计算总内存需加上它。

实战:批量处理 CSV 时的内存优化

当用 pd.read_csv() 读取大量文本列时,可以指定 dtype 参数为 'category',或者读取后用 astype 转换。更聪明的做法是让 Pandas 自动推断:使用 pd.read_csv(..., dtype='category') 会强制所有列都变 category,但可能过度。更好的策略是:先读取前 1000 行推断每列的唯一值比例,再决定哪些列转 category。

  1. 读取样本:sample = pd.read_csv('large.csv', nrows=1000)
  2. 计算每列唯一值占比:unique_ratio = sample.nunique() / len(sample)
  3. 对占比 < 0.5 的列转换:convert_cols = unique_ratio[unique_ratio < 0.5].index
  4. 正式读取时:df = pd.read_csv('large.csv', dtype={col: 'category' for col in convert_cols})

这样既能减少内存,又不会损失数值列的精度。

注意事项与陷阱

  • 排序问题 :category 列默认按字母排序,如需自定义顺序可用 pd.Categorical(..., categories=[...], ordered=True)
  • 缺失值 :NaN 会被视为一个特殊类别,cat.codes 中缺失值编码为 -1。
  • 性能影响:groupby 和 value_counts 在 category 列上通常更快,但某些操作(如字符串方法)需要先转换回 object。
  • 内存计算 :category 的总内存 = 编码数组(int8/16/32/64,根据类别数自动选择)+ 类别映射表,用 df.memory_usage(deep=True) 查看更准确。

总结

分类类型是 Pandas 优化内存的利器,特别适合低基数(唯一值少)的字符串列。通过 astype('category')read_csv 的 dtype 参数,可以轻松将内存占用降低一个数量级,同时保持代码简洁。下次处理大数据集时,不妨先检查重复列,用分类类型换取内存和速度的双赢。

相关推荐
2601_962298679 天前
Python:对象缓存优化机制(CPython)
python·性能优化·内存优化·cpython·对象缓存
~木雨18 天前
String 底层原理与常量池全解析:byte []+coder、intern 陷阱、substring 内存泄漏,一篇讲透
java·jvm·内存优化·string·字符串常量池
高心星3 个月前
鸿蒙6.0应用开发——应用内存占用优化
性能优化·生命周期·内存优化·图片处理·鸿蒙6.0·harmonyos6.0
审判长烧鸡4 个月前
Go 内存优化骚操作
go·内存优化
千里马-horse7 个月前
Building a Simple Engine -- Mobile Development -- Performance optimizations
shader·内存优化·rendering·纹理优化·vulkan·压缩格式
知无不研8 个月前
内存碎片与内存优化
开发语言·c++·内存优化·内存碎片·内存操作
_OP_CHEN9 个月前
【C++数据结构进阶】吃透 LRU Cache缓存算法:O (1) 效率缓存设计全解析
数据结构·数据库·c++·缓存·线程安全·内存优化·lru
Tom4i9 个月前
【内存优化】使用 Android Studio Profiler 分析 .hprof 文件
android·android studio·内存优化·内存泄漏
白鹿第一帅10 个月前
【Rust 探索之旅】Rust 性能优化实战指南:从编译器到并发的完整优化方案(附京东/华为云真实案例)
内存优化·白鹿第一帅·编译器优化·并发优化·rust性能优化·lto优化·rust性能分析