在Pandas中解析大型CSV文件的最快方法

Gin*_*ger 24 python pandas

我在这里使用熊猫来分析大数据文件:http://www.nielda.co.uk/betfair/data/它们的大小约为100兆.

来自csv的每个负载需要几秒钟,然后有更多时间来转换日期.

我已经尝试加载文件,将日期从字符串转换为日期时间,然后将它们重新保存为pickle文件.但加载它们也需要几秒钟.

我可以使用哪些快速方法从磁盘加载/保存数据?

jor*_*ris 19

正如@chrisb所说,熊猫的read_csv速度可能比csv.reader/numpy.genfromtxt/loadtxt.我不认为你会找到更好的解析csv(作为一个注释,read_csv不是'纯python'解决方案,因为CSV解析器是用C实现的).

但是,如果您必须经常加载/查询数据,解决方案是仅解析CSV一次,然后将其存储为另一种格式,例如HDF5.您可以使用pandas(PyTables在后台)有效地查询(docs).
请参阅此处,了解HDF5,csv和SQL与pandas的io性能:http://pandas.pydata.org/pandas-docs/stable/io.html#performance-considerations

还有一个可能相关的问题:"大数据"工作流程使用大熊猫


Mic*_*ado 7

稍后发布此内容是为了回答一个类似的问题,该问题发现简单地使用开箱即用的 modin 是不够的。答案与 dask 类似 - 根据您的用例,组合使用以下所有策略以获得最佳结果。

关于缩放到大型数据集的pandas 文档有一些很棒的技巧,我将在这里总结:

  1. 加载更少的数据usecols使用或nrows 参数pd.read_csv读入列或行的子集。例如,如果您的数据有很多列,但您只需要col1col2列,请使用pd.read_csv(filepath, usecols=['col1', 'col2'])。如果您要加载带有大量额外逗号的数据集(例如,行看起来像 ),这一点尤其重要。index,col1,col2,,,,,,,,,,,在这种情况下,请使用nrows仅读入数据的子集,以确保结果仅包含您需要的列。
  2. 使用有效的数据类型。默认情况下,pandas 将所有整数数据存储为有符号 64 位整数,将浮点数存储为 64 位浮点数,将字符串存储为对象或字符串类型(取决于版本)。您可以使用诸如Series.astype或 之pd.to_numeric类的downcast
  3. 使用分块。解析大数据块可能会很慢,特别是如果您的计划是按行操作然后将其写出或将数据缩减为较小的最终形式。您可以使用chunksizeiterator参数来循环数据块并以较小的片段处理文件。有关更多详细信息,请参阅逐块迭代文件的文档或者,使用该low_memory标志让 Pandas 在后端使用分块迭代器,但返回单个数据帧。
  4. 使用其他库。这里列出了几个很棒的库,但我特别要提到dask.dataframe,它专门针对您的用例,通过启用 CSV 文件的分块、多核处理来镜像pandas API并具有简单的转换方法处理数据后将数据返回到正常的 pandas 数据帧(如果需要)。

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

  1. 指定列数据类型。特别是如果分块,但即使您没有,指定列类型也可以显着减少读取时间和内存使用量,并突出显示数据中的问题区域(例如,NaN 指示器或不满足 pandas 默认值之一的标志)。使用dtypes具有单一数据类型的参数来应用于所有列或列名的字典,数据类型对指示要读入的类型。或者,您可以提供converters格式化日期、时间或其他数字数据(如果不在其中) pandas 识别的格式。
  2. 指定解析器引擎- pandas 可以用纯 python(慢)或 C(快得多)读取 csv。python 引擎具有更多的功能(例如,当前 C 解析器无法读取具有复杂多字符分隔符的文件,并且无法跳过页脚)。尝试使用该参数engine='c'来确保正在使用 C 引擎。如果您的文件无法被 C 引擎读取,我会尝试首先手动修复文件(例如,删除页脚或标准化分隔符),然后如果可能的话,使用 C 引擎进行解析。
  3. 确保捕获数字列中的所有 NaN 和数据标志。这可能是一项艰巨的任务,在输入中指定特定的数据类型有助于捕获不良情况。使用na_valueskeep_default_nadate_parser和 的converters参数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 重新启动。 -将整个列分类为对象列(对内存和速度来说超级不利!)。
  4. pd.read_csv一遍又一遍地阅读文档。read_csv 的许多参数都有重要的性能考虑。pd.read_csv经过优化以平滑可被视为 csv 的大量变化,并且更多的 magic pandas 必须准备好执行(确定类型、解释 nan、转换日期(可能)、跳过页眉/页脚、推断索引/列、处理坏行等)读取速度越慢。给它尽可能多的提示/约束,你可能会发现性能大幅提高!如果这还不够,其中许多调整也将适用于dask.dataframe API,因此这可以进一步很好地扩展。

此外,如果可以选择,请将文件保存为稳定的二进制存储格式。Apache Parquet是一种很好的列式存储格式,支持 pandas,但还有许多其他格式(有关更多选项,请参阅Pandas IO 指南)。Pickles 跨 Pandas 版本可能有点脆弱(当然,任何二进制存储格式也一样,但这通常不太关心显式数据存储格式而不是 Pickles),并且 CSV 效率低下且未指定,因此需要类型转换和解释。


DrV*_*DrV 4

要检查的一件事是磁盘系统本身的实际性能。特别是如果您使用旋转磁盘(而不是 SSD),您的实际磁盘读取速度可能是性能的解释因素之一。因此,在进行太多优化之前,请检查将相同的数据读入内存(例如,mydata = open('myfile.txt').read())是否需要相同的时间。(只要确保你没有被磁盘缓存咬住;如果你加载相同的数据两次,第二次会快得多,因为数据已经在 RAM 缓存中了。)

在相信我在下面写的内容之前请参阅下面的更新

如果您的问题确实是解析文件,那么我不确定是否有任何纯 Python 解决方案可以帮助您。由于您知道文件的实际结构,因此不需要使用通用 CSV 解析器。

不过,可以尝试三件事:

  1. Pythoncsv包和csv.reader
  2. 数值模拟genfromtext
  3. 麻木loadtxt

如果您可以将其与您的数据一起使用,那么第三个可能是最快的。同时它具有最有限的功能集。(这实际上可能会使其变得更快。)

crclayton另外, 、 、BKay、 、 等评论中给你的建议都EdChum很好。

尝试不同的选择!如果它们不起作用,那么您将不得不用编译语言(编译的 Python 或 C)编写一些东西。

更新:我确实相信chrisb下面所说的,即pandas解析器很快。

那么使解析速度更快的唯一方法是用 C(或其他编译语言)编写特定于应用程序的解析器。CSV 文件的通用解析并不简单,但如果知道文件的确切结构,可能会有快捷方式。在任何情况下,解析文本文件都很慢,因此如果您可以将其转换为更容易接受的内容(HDF5、NumPy 数组),则加载将仅受 I/O 性能的限制。

  • 就其价值而言,pandas csv 解析器比这三个解析器中的任何一个都快得多。 (3认同)