Pandas Dataframe 内存占用
一个 n 行 m 列的 DataFrame,如果不指定列的数据类型,pandas 会默认使用 object 类型,并使用 None 填充数据,None 本身占用16个字节,外加8个字节的引用计数,和8个字节的类型指针,一个数据需要占用32个字节,总共占用 32*n*m
字节。
所以,如果不指定数据类型,DataFrame 的内存占用会非常大。
内存优化
如果知道数据的类型,可以在创建 DataFrame 时指定数据类型,可以减少内存占用。
对于字符串类型,会按照字符串本身的长度,占用不同的大小。
占用内存最小的是 int8 类型,占用 1 个字节。
category 类型
对于分类数据,可以使用 category 类型,相比直接存储字符串,会节省更多内存。
在 pandas 中,使用 category 数据类型可以节省内存的主要原因是它使用整数编码来代表数据中的类别,而不是直接存储字符串或其他数据类型。这种方法在处理包含重复值多的离散数据时尤其有效。以下是详细解释:
- 整数编码
category 类型背后的核心是,它将每一个唯一的类别映射到一个整数值。这种映射是内部进行的,对用户透明。例如,如果你有一个列,包含数千次重复的几个字符串值(如状态名称、产品类别等),使用 category 类型存储时,每个唯一的字符串值都被映射到一个唯一的整数编码。这些整数编码通常占用的空间远小于原始字符串。- 内存使用
字符串存储:在默认情况下,字符串通常存储为 object 类型,这意味着 pandas 在底层使用 Python 字符串对象来存储每个值。Python 的字符串对象是相对昂贵的,因为除了字符串内容本身,每个对象还需要额外的内存来存储对象管理的开销。
整数存储:相比之下,整数占用的内存较少,通常是固定的(例如 int8 类型占用 1 字节,int16 类型占用 2 字节等),并且不需要额外的管理开销。- 查找效率和存储优化
使用 category 类型时,pandas 只需要在内部维护一个唯一类别的列表,所有的操作(如排序、分组)都可以通过操作整数索引来进行,这不仅提高了处理速度,还减少了内存占用。此外,对于有限的唯一值集,整数映射比存储大量重复的字符串要高效得多。
实际场景
在「AI筛词」工具开发过程中,有以下场景:
n 个关键词,m1 个一级分类,每个一级分类下包含 m2 的二级分类。
关键词为字符串类型,一个关键词平均占用100字节;二级分类为字符串,一个二级分类平均占用30个字节。
分类平铺
分类平铺,表示将所有二级分类都展开成为一级分类,总共会有 m1*m2
列,每一列使用 0 或 1 表示是否属于该分类。
关键词 | 一级分类1-二级分类1 | 一级分类1-二级分类2 | 一级分类2-二级分类1 |
---|---|---|---|
关键词1 | 1 | 0 | 0 |
如果使用分类平铺的方式,则一共有m1*m2 + 1
个列,除了关键词列,其他列都是 int8 类型,关键词列是字符串类型,占用内存为:
100*n + m1*m2*1
分类嵌套
分类嵌套,表示将二级分类嵌套在一级分类下,总共会有 m1 + 1
列,每一列使用 0 或 1 表示是否属于该分类。
关键词 | 一级分类1 | 一级分类2 | 一级分类3 |
---|---|---|---|
关键词1 | 二级分类1 | 二级分类2 | 二级分类1 |
如果使用分类嵌套的方式,则一共有 m1 + 1
个列,除了关键词列,其他列都是 字符串类型,关键词列是字符串类型,占用内存为:
100*n + m1*30
使用 category 类型
基于 分类嵌套 的方式,设置每个一级分类的列为 category 类型,占用内存为:
100*n + m1*1
这里忽略了Index的内存占用。