使用pyarrow的Pandas在拆分数据框时不占用额外内存

3 投票
1 回答
45 浏览
提问于 2025-04-14 17:27

在使用 float64[pyarrow] 数据类型的 Pandas 2.2.1 时,发现把一个数据表分成两部分后再合并回来,似乎并没有使用额外的内存。

而如果使用普通的 float64 数据类型,内存的使用量是原数据表的三倍(这也是我直觉上认为的,如果数据表被复制的话)。

有没有人能解释一下这是为什么?这显然是个好事,但在 pyarrow 的好处 中似乎没有提到,所以我想了解一下原因。

我运行的代码是:

import gc
import os

import numpy as np
import pandas as pd
import psutil


def log_memory_usage():
    gc.collect()
    pid = os.getpid()
    p = psutil.Process(pid)
    full_info = p.memory_info()
    print(
        f"Memory usage: {full_info.rss / 1024 / 1024:.2f} MB (RSS)"
    )


log_memory_usage()
df1 = pd.DataFrame(np.ones(shape=(10000000, 10)), columns=[f"col_{i}" for i in range(10)], dtype="float64")
log_memory_usage()
split1 = df1.loc[:, df1.columns[:5]]
split2 = df1.loc[:, df1.columns[5:]]
log_memory_usage()
joined_again = pd.concat([split1, split2], axis=1)
log_memory_usage()

这段代码打印出:

Memory usage: 68.28 MB (RSS), 33685.60 MB (VMS),  68.29 MB (Peak RSS)
Memory usage: 831.38 MB (RSS), 34448.54 MB (VMS),  831.38 MB (Peak RSS)
Memory usage: 1594.66 MB (RSS), 35211.49 MB (VMS),  1594.66 MB (Peak RSS)
Memory usage: 2346.45 MB (RSS), 35974.43 MB (VMS),  2346.45 MB (Peak RSS)

所以每次分割和合并数据表都会使用额外的内存。

但是如果我把 dtype="float64" 改成 dtype="float64[pyarrow]",我得到的输出是:

Memory usage: 68.14 MB (RSS)
Memory usage: 833.51 MB (RSS)
Memory usage: 833.84 MB (RSS)
Memory usage: 833.93 MB (RSS)

所以看起来在分割和合并后的数据表中,使用的额外内存非常少。

1 个回答

1

这看起来是一个叫做写时复制的优化方法。如果我在代码中加上这个:

pd.set_option("mode.copy_on_write", True)

那么这两种数据类型都会减少内存的使用。

所以也许pyarrow默认就开启了写时复制?不过我在文档里找不到相关的信息。

撰写回答