pandas到_csv块大小的经验法则如何设置chunksize?

hfwmuf9z  于 2023-09-28  发布在  其他
关注(0)|答案(2)|浏览(83)

当你用df.to_csv(...)写一个大的 Dataframe 时,它有时会阻塞你的内存。在这种情况下,设置chunksize会有所帮助。参见docs
决定块大小的好规则是什么?现在我只是从1 e6开始,然后按数量级降低它,直到它起作用。
我想象一些经验法则(MB-free / size_per_row * 0.9)。想知道是否有人有一个合理的,理想的程序决定。

eyh26e7m

eyh26e7m1#

别太过火了。想想你得到了什么,失去了什么。
使用更大的内存缓冲区可以保存什么:

  • 你减少了系统调用的次数
  • 您可以减少通过网络文件系统的网络往返次数

使用更大的缓冲区会损失什么:

  • 总体上您会花费更多的内存
  • 降低CPU缓存效率。一旦超过L2缓存大小(通常为128 - 256 kiB),内存带宽就开始成为一个问题;一旦超过L3缓存大小(几MiB),内存带宽就成为一个主要问题

根据我的经验,对于本地文件系统,4 kiB - 64 kiB的传输大小是不错的。对于网络文件系统,您可能希望更大,例如1 MiB。但没有硬边界。你只会得到递减的回报,在某个时候会稍微慢下来。
现在的问题是,您以行而不是字节为单位给予大小。这取决于你的格式。当然,您可以估计行的大小,但我认为这是多余的,因为您不需要精确。每行80个字符,则每4 kiB有51行,每64 kiB有819行,每1 MiB有13107行。因此,使用100、1000或10,000行似乎是合理的。
当然,你可以简单地对它进行基准测试。

import sys

import numpy as np
import pandas as pd

def main():
    outpath = sys.argv[1]
    rows, chunksize = (int(arg) for arg in sys.argv[2:])
    df = pd.DataFrame(data={
        'colA': np.random.random(rows), 'colB': np.random.random(rows),
        'colC': np.random.random(rows), 'colD': np.random.random(rows)})
    df.to_csv(outpath, chunksize=chunksize)

if __name__ == '__main__':
    main()

在我的系统中,块大小为100时,我在4.3秒内获得100万行,1000时为3.6秒,10,000时为3.4秒,100,000时为3.6秒。
大部分时间都花在了格式化输出上。缓冲区大小是次要的。取一个合理的数字,然后完成它。如果有的话,花时间切换到更合理的二进制格式。

6kkfgxo0

6kkfgxo02#

可能的策略之一:

import psutil

def calc_chunksize(df, share=0.3):
    """Estimate optimal chunksize (in records) for writing large dfs with df.to_csv"""

    # get approximate record size in bytes
    row_size = df.memory_usage(index=True, deep=True).sum() / df.index.size
    # get share of available memory size in bytes
    avail_mem = psutil.virtual_memory().available * share

    return int(avail_mem / row_size)

根据您自己的判断来管理share属性(考虑到其他进程根据其活动可能动态地需要一些可用内存)。

相关问题