Pandas中DataFrame直接采样与赋值后采样的性能差异疑问
问题分析与解决
为啥两种操作速度差这么多?
先给你吃个定心丸:df2 = df根本没复制那70GB数据,只是给同一个DataFrame多了个“别名”,内存里从头到尾只有一份原数据,完全不用担心占双倍内存。
速度差异的关键原因和内存管理、系统内存压力有关:
- 直接跑
df = df.sample(100000)时,采样过程中会先生成10万行的新小DataFrame,而原来的70GB大表在赋值完成前,还被df这个变量挂着。这时候内存里同时塞着大表、小表,再加上采样时的临时数据,直接撑爆物理内存,逼得系统开始用硬盘当内存(也就是swap)——硬盘读写速度比内存慢几百上千倍,这就是为啥要等10分钟。 - 先赋值
df2 = df再采样就不一样了:原大表的引用被df2拿着,当df被替换成小表后,原大表还没被立刻回收,但采样过程中,pandas不需要同时处理“原对象释放”这件事,内存压力没那么大,不会触发swap,自然几秒就搞定。
另外还有一种可能:如果你的df是从其他大表切出来的视图(不是独立副本),直接对视图采样时,pandas会先把视图转成完整副本(等于要复制70GB数据,能不慢吗?);而赋值df2 = df后,pandas会直接用原数据的底层存储来采样,跳过了转副本的步骤,速度直接起飞。
怎么高效采样又不占额外内存?
既然df2 = df不占额外内存,放心用就行。要是不想留df2这个变量,采样完删了就行:
df2 = df df = df2.sample(100000) del df2 # 手动删掉别名,帮系统早点回收大表内存 import gc gc.collect()
嫌麻烦的话,也可以用浅拷贝代替赋值,写法更简洁:
df = df.copy(deep=False).sample(100000)
copy(deep=False)就是创建一个新的DataFrame对象,但和原表共享内存块,本质和df2 = df一模一样,不占额外内存,还能触发高效采样的逻辑。
内容的提问来源于stack exchange,提问作者n_arch
相关产品推荐
相关产品推荐

