【问题标题】:Is there a faster way to concat huge data frames (40GB) using pandas有没有更快的方法来使用 pandas 连接巨大的数据帧(40GB)
【发布时间】:2019-11-13 15:28:20
【问题描述】:

我有 3 个 40 GB 大小的巨大数据帧,我使用块打开它们。然后,我想将它们连接在一起。这是我尝试过的:

    path = 'path/to/myfiles'
    files = [os.path.join(path,i) for i in os.listdir(path) if i.endswith('tsv')]
    for file in files:
        cols = ['col1','col2','col3']
        chunks = pd.read_table(file, sep='\t', names=cols, chunksize=10000000)

但是,当我尝试连接所有文件时,它需要很长时间。 我想有一些建议可以更快/更快地连接所有数据帧。

【问题讨论】:

  • 您查看过dask 吗?我自己还没有机会使用它,但我听说过这个项目的好消息,而且数据太大而无法放入内存。
  • 感谢您的建议!这个我没研究过,会看的。
  • 但是您真的需要为您的用例将整个数据帧保存在内存中吗?有其他文件格式(HDFS、PARQUET 等),还有concat 的替代命令。如果您告诉我们您主要需要列访问还是行访问,以及顺序访问还是随机访问,这将很有帮助。 (例如,您可以只串行处理每个(连接的)行,还是跨多列进行任意过滤,还是什么?)
  • 您还说运行时很慢,但您可能反而会耗尽内存。注意pd.read_table(..., chunksize=1e7)参数不是内存块的大小;它是块中的行数。用于块的实际内存取决于每个数据帧中一行的大小,因此如果一个组合行占用 10Kb,则尝试使用其中的 chunksize=1e7 将占用 100Gb,这是巨大的。尝试较低的块大小。此外,您永远不应该将这样的常量硬连线到您的源代码中,尤其是。如果它们会导致您的工作在大多数中型机器上失败。

标签: pandas performance memory concat


【解决方案1】:
  1. CSV/TSV 是一种非常慢的文件格式,没有经过优化。
  2. 您可能不需要将整个数据集保存在内存中。您的用例可能不需要对整个组合 (120GB) 数据集进行完全随机的列和行访问
  • (您能否连续处理每一行/块/组(例如 zipcode、user_id 等)?例如计算聚合、汇总统计信息、特征?或者您是否需要能够跨列应用任意过滤器(哪些列),还是行(哪些列)?例如“获取过去 N 天内使用服务 X 的所有用户 ID”。您可以根据自己的用例选择性能更高的文件格式。有替代文件格式(HDFS、PARQUET 等)有些针对列访问或行访问进行了优化,有些针对顺序或随机访问进行了优化。还有 PySpark。
  • 您不一定需要将数据集合并到一个巨大的 120GB 文件中。
  1. 您是说运行时速度很慢,但很可能您正在耗尽内存(在这种情况下运行时超出了窗口),因此您首先检查您的内存使用情况。
  • 您的代码正在尝试读取并存储每个文件的所有块,而不是跨三个文件逐块处理它们for file in files: ... chunks = pd.read_table(file, ... chunksize=10000000)。见Iterating through files chunk by chunk, in pandas
  • 修复后,chunksize=1e7 参数不是内存块的大小;它只是块中的行数。这个价值大得离谱。如果组合数据帧中的一行占用 10Kb,那么 1e7 行的一大块将占用 100Gb(!),这在大多数机器中都无法容纳。
  1. 如果您必须坚持使用 CSV,在三个文件中的每一个中处理一个块,然后将其输出写入文件,不要将所有块留在内存中。 另外减少你的块大小(尝试例如 1e5 或更少,并测量内存和运行时改进)。也不要对其进行硬编码,为每台机器找出一个合理的值,和/或将其设为命令行参数。监控您的内存使用情况。

【讨论】:

    【解决方案2】:

    .tsv.csv 是读/写相当慢的格式。我发现镶木地板最适合我最终做的大多数事情。它的读写速度非常快,并且还允许您轻松地将文件的分块文件夹作为单个表读回。但是,它确实需要字符串列名:

    In [102]: df = pd.DataFrame(np.random.random((100000, 100)), columns=[str(i) for i in range(100)])
    
    In [103]: %time df.to_parquet("out.parquet")
    Wall time: 980 ms
    
    In [104]: %time df.to_csv("out.csv")
    Wall time: 14 s
    
    In [105]: %time df = pd.read_parquet("out.parquet")
    Wall time: 195 ms
    
    In [106]: %time df = pd.read_csv("out.csv")
    Wall time: 1.53 s
    

    如果您无法控制这些分块文件的格式,您显然需要至少支付一次它们的读取成本,但从长远来看,转换它们仍然可以为您节省一些时间做很多其他的读/写。

    【讨论】:

      猜你喜欢
      • 2020-05-04
      • 2020-04-30
      • 2019-10-17
      • 1970-01-01
      • 2018-05-24
      • 2018-07-25
      • 2020-07-25
      • 1970-01-01
      • 2023-04-10
      相关资源
      最近更新 更多