咨询:Pandas内嵌numpy数组序列化前后memory_usage不一致的原因
Pandas DataFrame序列化/反序列化后内存使用量差异巨大的原因
我在测试Pandas DataFrame的pickle序列化/反序列化时,发现内存使用量出现了极大差异,想请人解释原因。目前我注意到一个线索:原始DataFrame中df["data"][0].flags的OWNDATA属性,和反序列化后的对应属性不同。
测试代码如下:
import pandas as pd import numpy as np import pickle df = pd.DataFrame({ "data": [np.random.randint(size=1024, low=0, high=100, dtype=np.int8) for _ in range(1_000_000)] }) print(df["data"].size, df["data"].dtype, df.memory_usage(index=True, deep=True).sum()) # 输出:1000000 object 1144000132 df2 = pickle.loads(pickle.dumps(df)) print(df2["data"].size, df2["data"].dtype, df2.memory_usage(index=True, deep=True).sum()) # 输出:1000000 object 120000132 print(np.array_equal(df["data"][0], df2["data"][0])) # 输出:True
核心原因:数组内存从独立存储变为共享视图
原始DataFrame的内存结构
你创建的原始DataFrame中,data列的每个元素都是独立的numpy数组,每个数组的OWNDATA=True——这意味着每个数组都拥有自己独立的1024字节数据缓冲区(因为是int8类型,1024个元素占1024字节)。再加上每个numpy对象本身的内存开销,100万个这样的独立数组会占用大量内存,这就是原始内存使用量高的原因。反序列化后的优化机制
Pandas在pickle序列化object列中的numpy数组时,会对相同结构(形状、dtype一致)的数组进行批量优化存储:把所有数组的数据打包成一个连续的大内存缓冲区,反序列化时,不会重新创建100万个独立数组,而是生成指向这个大缓冲区的视图(即OWNDATA=False的数组)。这些视图共享同一个底层数据缓冲区,不需要为每个数组单独存储数据,因此总内存使用量骤降。验证共享内存的证据
你可以通过查看数组的base属性验证这一点:# 原始数组的base都是None(自己拥有数据) print(df["data"][0].base is None) # True print(df["data"][1].base is None) # True # 反序列化后的数组base指向同一个大缓冲区 print(df2["data"][0].base is df2["data"][1].base) # True数据一致性不受影响
虽然内存存储方式变了,但每个视图的数据内容和原始数组完全一致,这也是np.array_equal返回True的原因——视图只是对底层数据的引用,读取数据时和独立数组没有区别。
内容的提问来源于stack exchange,提问作者richliaw
相关产品推荐
相关产品推荐

