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

36 投票
5 回答
44062 浏览
提问于 2025-04-18 18:35

我正在使用pandas来分析很大的CSV数据文件。这些文件大约有100兆字节。

每次从CSV文件加载数据都需要几秒钟,然后还要花更多时间来把日期转换成日期时间格式。

我尝试过加载这些文件,把日期从字符串格式转换成日期时间格式,然后再把它们保存为pickle文件。但加载这些pickle文件也需要几秒钟。

我可以用什么快速的方法来从磁盘加载或保存数据呢?

5 个回答

0

这里的大部分解决方案都很有帮助,我想说并行加载也能帮上忙。下面是简单的代码示例:

import os
import glob
path = r'C:\Users\data' # or whatever your path
data_files = glob.glob(os.path.join(path, "*.psv")) #list of all the files to be read

import reader
from multiprocessing import Pool

def read_psv_all (file_name):
    return pd.read_csv(file_name,
                       delimiter='|',  # change this as needed                              
                       low_memory=False
                      ) 

pool = Pool(processes=3) # can change 3 to number of processors you want to utilize
df_list = pool.map(read_psv_all, data_files) 
df =  pd.concat(df_list, ignore_index=True,axis=0, sort=False) 

需要注意的是,如果你在使用Windows或者Jupyter的时候,使用并行处理可能会有点麻烦。你可能需要在代码中加上 if __name__ == '__main__' 这一行。此外,利用列和数据类型(dtypes)也会对你有很大帮助。

0

Modin是加州大学伯克利分校RISELab的一个早期项目,旨在帮助数据科学领域更好地使用分布式计算。它是一个多进程的数据框架库,跟pandas的使用方法完全一样,这样用户就可以加快他们在Pandas中的工作流程。

在一台有8个核心的机器上,Modin可以让Pandas的查询速度提高4倍,用户只需要在他们的代码中改一行就可以了。

pip install modin

如果使用dask的话

pip install modin[dask]

可以通过输入以下代码来导入modin

import modin.pandas as pd

它会利用所有的CPU核心来导入csv文件,使用起来几乎和pandas一样。

4

首先要检查的是磁盘系统的实际性能。特别是如果你使用的是传统的旋转硬盘(而不是固态硬盘),那么你的磁盘读取速度可能会影响整体性能。所以,在进行过多优化之前,先检查一下读取同样的数据到内存中(比如用 mydata = open('myfile.txt').read() 这行代码)所花的时间是否差不多。要注意的是,如果你两次加载同样的数据,第二次会快很多,因为数据已经在内存缓存中了。

在相信我下面写的内容之前,请先查看下面的更新

如果你的问题真的是文件解析方面的,那么我不确定纯Python的解决方案是否能帮到你。因为你已经知道文件的具体结构,所以不需要使用通用的CSV解析器。

不过,有三种方法可以尝试:

  1. Python的 csv 包和 csv.reader
  2. NumPy的 genfromtext
  3. NumPy的 loadtxt

第三种方法可能是最快的,如果你能用它处理你的数据。同时,它的功能也最有限。(这实际上可能让它更快。)

另外,crclaytonBKayEdChum 在评论中给出的建议也很不错。

尝试不同的选择!如果这些方法都不行,那么你可能需要用编译语言写点东西(比如编译后的Python或者C语言)。

更新:我相信 chrisb 下面说的,pandas 的解析器是很快的。

那么,想要加快解析速度的唯一方法就是用C语言(或其他编译语言)写一个特定应用的解析器。通用的CSV文件解析并不简单,但如果知道文件的确切结构,可能会有一些捷径。无论如何,解析文本文件的速度都比较慢,所以如果你能把它转换成更易处理的格式(比如HDF5或NumPy数组),加载速度就只会受到输入输出性能的限制。

7

我在这里发这个是为了回应一个类似的问题,发现直接使用modin并没有达到预期效果。接下来的回答和dask也类似——结合下面所有策略来获得最佳效果,具体要根据你的使用场景来选择。

关于如何处理大数据集,pandas的文档中有一些很好的建议,我在这里总结一下:

  1. 少读一些数据。使用usecolsnrows参数来读取部分列或行,具体可以用在pd.read_csv中。例如,如果你的数据有很多列,但你只需要col1col2这两列,可以用pd.read_csv(filepath, usecols=['col1', 'col2'])。如果你的数据中有很多多余的逗号(比如行看起来像index,col1,col2,,,,,,,,,,,),这点尤其重要。在这种情况下,使用nrows只读取一部分数据,以确保结果中只包含你需要的列。
  2. 使用高效的数据类型。默认情况下,pandas会把所有整数数据存储为64位有符号整数,浮点数存储为64位浮点数,字符串则存储为对象或字符串类型(具体取决于版本)。你可以使用Series.astypepd.to_numeric配合downcast选项将这些数据转换为更小的数据类型。
  3. 使用分块处理。处理大块数据可能会很慢,特别是如果你打算逐行操作然后写出结果,或者将数据缩减到更小的最终形式。你可以使用chunksizeiterator参数来循环处理数据块,以较小的部分处理文件。有关更多细节,请查看逐块迭代文件的文档。或者,可以使用low_memory标志让Pandas在后台使用分块迭代器,但返回一个单一的数据框。
  4. 使用其他库。这里有几个很好的库,但我特别推荐dask.dataframe,它专门针对你的使用场景,支持对CSV文件进行分块、多核处理,且与pandas API相似,处理完数据后还可以轻松转换回普通的pandas数据框(如果需要的话)。

此外,还有一些特定于CSV的事项你应该考虑:

  1. 指定列的数据类型。特别是在使用分块时,即使不使用,指定列类型也能显著减少读取时间和内存使用,并突出数据中的问题区域(例如,NaN指示符或不符合pandas默认值的标志)。使用dtypes参数,可以为所有列应用单一数据类型,或者使用列名和数据类型的字典来指明要读取的类型。如果数据格式不被pandas识别,你还可以提供converters来格式化日期、时间或其他数值数据。
  2. 指定解析引擎 - pandas可以用纯Python(慢)或C(快得多)来读取CSV。Python引擎有一些额外功能(例如,当前C解析器无法读取复杂的多字符分隔符的文件,也无法跳过文件尾部)。尝试使用参数engine='c'来确保使用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,那么这将被忽略,可能会导致错误(如果你指定了数据类型),或者导致pandas将整个列重新分类为对象列(这对内存和速度来说非常糟糕!)。
  4. 多次阅读pd.read_csv的文档。许多read_csv的参数对性能有重要影响。pd.read_csv经过优化,可以处理各种不同格式的CSV,pandas需要准备的“魔法”越多(确定类型、解释NaN、转换日期(可能)、跳过头部/尾部、推断索引/列、处理错误行等),读取速度就会越慢。尽量给它提供更多的提示和约束,你可能会看到性能大幅提升!如果仍然不够,许多这些调整也适用于dask.dataframe API,因此可以很好地扩展。

此外,如果有选择的话,建议将文件保存为稳定的二进制存储格式。Apache Parquet是一种很好的列式存储格式,支持pandas,但还有很多其他选项(可以查看Pandas IO指南以获取更多选择)。Pickles在不同的pandas版本之间可能会有些脆弱(当然,任何二进制存储格式都可能如此,但对于明确的数据存储格式来说,这通常不是大问题),而CSV效率低且规范不明确,因此需要进行类型转换和解释。

27

正如@chrisb所说,pandas的read_csv功能可能比csv.reader/numpy.genfromtxt/loadtxt要快。我觉得你很难找到比这个更好的方法来解析CSV文件(顺便提一下,read_csv并不是一个“纯Python”的解决方案,因为它的CSV解析器是用C语言实现的)。

不过,如果你需要频繁加载或查询数据,一个好的方法是只解析一次CSV文件,然后把它存储成其他格式,比如HDF5。你可以使用pandas(后台用的是PyTables)来高效地查询这些数据(文档)。
这里有一个关于HDF5、CSV和SQL在pandas中性能比较的链接:http://pandas.pydata.org/pandas-docs/stable/io.html#performance-considerations

还有一个可能相关的其他问题:“使用pandas处理大数据”的工作流程

撰写回答