【问题标题】:Is there a way to speed up handling large CSVs and dataframes in python?有没有办法加快在 python 中处理大型 CSV 和数据帧?
【发布时间】:2021-09-12 15:51:53
【问题描述】:

我正在处理一些大小在 1Gb 到 2Gb 之间的 CSV 文件。将文件加载到 pandas 数据框中需要 20-30 分钟,而我执行的每个操作需要 20-30 分钟,例如按列名过滤数据框,打印 dataframe.head() 等。有时,当我在等待时尝试使用另一个应用程序时,它也会滞后于我的计算机。我使用的是 2019 年的 Macbook Pro,但我想其他设备也一样。

我尝试过使用 modin,但数据操作仍然很慢。

有什么方法可以让我工作更有效率?

提前感谢您的回复。

【问题讨论】:

  • 你对这些文件做了什么?每次操作都需要读入整个文件吗?
  • 听起来你的可用内存太少了。
  • 使用活动监视器查看您是否正在交换 - 您可能需要更多内存。如果您不需要所有列,usecols 可以限制保留的内容。如果您多次使用相同的 csv,请将它们保存到 parquet 之类的文件中。如果某些数据使您无法使用像 int64 这样的小型 dtype(例如,由于空行而最终得到 object),请先使用 csv 模块逐行清理 csv。 Apache箭头可以帮助arrow.apache.org/docs/python
  • 这些症状暗示您的处理耗尽了可用内存。解决方案:要么购买更多内存,如果您可以添加一些到您的机器或购买一台具有更多内存的计算机,或者如果有意义,请尝试不将整个文件加载到内存中。对于简单的操作,使用 csv 模块一次处理一行文件是模块并且只需要很少的内存,无论文件大小...
  • @norie 我正在从一个大型 CSV 文件中选择列,然后将其转换为一个 numpy 数组以与 tensorflow 一起使用。

标签: python pandas dataframe csv


【解决方案1】:

Scaling to Large Datasets 上的 pandas 文档有一些很棒的技巧,我将在这里总结一下:

  1. Load less data。使用usecolsnrows parameters to pd.read_csv 读入列或行的子集。例如,如果您的数据有很多列,但您只需要col1col2 列,请使用pd.read_csv(filepath, usecols=['col1', 'col2'])。如果您要加载带有大量额外逗号的数据集(例如,行看起来像 index,col1,col2,,,,,,,,,,,。在这种情况下,请使用 nrows 仅读取数据的子集以确保仅读取结果包括您需要的列。
  2. Use efficient datatypes。默认情况下,pandas 将所有整数数据存储为有符号 64 位整数,浮点数存储为 64 位浮点数,字符串存储为对象或字符串类型(取决于版本)。您可以使用带有downcast 选项的Series.astypepd.to_numeric 等工具将这些转换为更小的数据类型。
  3. Use Chunking。解析大块数据可能会很慢,特别是如果您的计划是按行操作然后将其写出或将数据缩减为更小的最终形式。或者,使用 low_memory 标志让 Pandas 在后端使用分块迭代器,但返回单个数据帧。
  4. Use other libraries。这里列出了几个很棒的库,但我要特别提到 dask.dataframe,它专门针对您的用例,通过启用与 the pandas API 镜像的 CSV 文件的分块、多核处理并具有简单的转换方法处理数据后,将数据返回到普通的 pandas 数据帧(如果需要)。

此外,我认为您应该考虑一些特定于 csv 的事情:

  1. Specifying column data types。特别是在分块的情况下,但即使您不这样做,指定列类型也可以显着减少读取时间和内存使用量,并突出显示数据中的问题区域(例如,不符合熊猫默认值之一的 NaN 指示符或标志)。使用带有单一数据类型的dtypes 参数应用到所有列或列名的字典,数据类型对指示要读入的类型。可选地,您可以提供converters 来格式化日期、时间或其他如果不是 pandas 识别的格式的数字数据。
  2. Specifying the parser engine - pandas 可以在纯 python(慢)或 C(快得多)中读取 csvs。 python 引擎具有更多功能(例如,目前 C 引擎无法读取具有复杂多字符分隔符的文件,并且它无法跳过页脚)。尝试使用参数engine='c' 来确保正在使用 C 引擎。如果您需要其中一种不受支持的文件类型,我会先尝试手动修复文件(例如去除页脚),然后尽可能使用 C 引擎进行解析。
  3. 确保您在数字列中捕获所有 NaN 和数据标志。这可能是一项艰巨的任务,在您的输入中指定特定的数据类型有助于捕获不良情况。将na_valueskeep_default_nadate_parserconverters 参数用于pd.read_csv。目前,解释为 NaN 的默认值列表是 ['', '#N/A', '#N/A N/A', '#NA', '-1.#IND', '-1.#QNAN', '-NaN', '-nan', '1.#IND', '1.#QNAN', '<NA>', 'N/A', 'NA', 'NULL', 'NaN', 'n/a', 'nan', 'null']。例如,如果您的数字列具有编码为 notANumber 的非数字值,那么这将被遗漏并且会导致错误(如果您指定了 dtypes)或者会导致 pandas 将整个列重新分类为对象列(suuuper 对内存和速度不利!)。
  4. 一遍又一遍地阅读pd.read_csv 文档。 read_csv 的许多参数都有重要的性能考虑。 pd.read_csv 进行了优化,可以平滑被认为是 csv 的大量变化,并且必须准备好执行更多神奇的 pandas(确定类型、解释 nans、转换日期(可能)、跳过页眉/页脚、推断索引/列,处理坏行等)读取速度越慢。给它尽可能多的提示/约束,你可能会看到性能提升很多!如果这还不够,这些调整中的许多也将适用于 dask.dataframe API,因此可以进一步扩大规模。

【讨论】:

  • 非常感谢您的详细回复。我会尝试其中一些。
  • 我已经添加了更多指针 - 抱歉,我在中途不小心点击了发布! :) 祝你好运
【解决方案2】:

这可能对您有所帮助,也可能无济于事,但我发现将数据存储在 HDF 文件中显着提高了 IO 速度。如果您最终是 CSV 文件的来源,我认为您应该尝试将它们存储为 HDF。否则迈克尔已经说过的可能是要走的路。

【讨论】:

  • 有很多好的二进制文件格式,其中一些非常适合列式数据,包括apache parquet 格式,pandas supports 通过DataFrame.to_parquetpd.read_parquet 方法,如果您安装 pyarrowfastparquet 库之一。
  • (如果不清楚 - 这是为了增加您的答案而不是矛盾)。 @SMeznaric 是非常重要的一点——只要有可能——当性能或精度很重要时,尽可能转换为二进制格式! CSV 是一种过于杂乱且效率低下的存储介质。它是稳定的(部分原因是缺乏技术规范)并且它是人类可读的,所以它对数据科学家来说是很好的安全工作lol
【解决方案3】:

考虑使用polars。它通常比熊猫快几个数量级。以下是支持 claim 的一些基准。

如果您真的想要完整的性能,请考虑使用惰性 API。您描述的所有过滤器甚至可以在扫描级别完成。我们还可以使用pl.collect_all() 轻松并行化所有文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-20
    • 2022-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多