Python:检索文件中逗号分隔数据的最快方法

时间:2013-10-18 02:04:03

标签: python

我有一个几十万行的文件,看起来像这样:

01,T,None,Red,Big
02,F,None,Purple,Small
03,T,None,Blue,Big
.......

我想要从整个文件中检索 n 列的内容。例如,第4列将是:

Red
Purple
Blue

由于文件很大,我很想知道最有效的方法。

显而易见的解决方案是逐行浏览文件,然后应用split(',')并获取数组中的第4项,但我想知道是否有更好的内容。

3 个答案:

答案 0 :(得分:6)

我认为您只需阅读文件并使用str.split()即可。但是,您没有向我们展示您的所有代码......您可能希望确保在处理之前没有将整个文件读入内存(使用file.readlines()方法函数或file.read() )。

这样的事情可能和你一样好:

with open(filename, "rt") as f:
    for line in f:
        x = line.split(',')[3]
        # do something with x

如果您希望能够将输入文件视为仅包含一列,我建议将上述内容包含在使用yield提供值的函数中。

def get_col3(f):
    for line in f:
        yield line.split(',')[3]

with open(filename, "rt") as f:
    for x in get_col3(f):
        # do something with x

鉴于文件I / O内容是Python的C内容的一部分,你可能不会因为棘手而无法获得太多的额外速度。但你可以尝试编写一个简单的C程序来读取文件,查找第四列,然后将其打印到标准输出,然后将其输入到Python程序中。

如果你将使用相同的输入文件,将它保存为某种二进制文件格式可能是有意义的,这种格式比解析文本文件更快。我相信那些使用像HDF5这样的大型数据集的科学家,而且Python通过Pandas对它有很好的支持。

http://pandas.pydata.org/

http://www.hdfgroup.org/HDF5/

嗯,现在我考虑一下:你应该尝试使用Pandas导入该文本文件。我记得Pandas的作者说他写了一些低级代码,大大加速了解析输入文件。

哦,找到了它:http://wesmckinney.com/blog/a-new-high-performance-memory-efficient-file-parser-engine-for-pandas/

嗯。查看Pandas文档,您可以使用带有可选参数read_csv()的{​​{1}}来指定所需列的子集,并且它将丢弃所有其他内容。

http://pandas.pydata.org/pandas-docs/stable/generated/pandas.io.parsers.read_csv.html

我认为Pandas可能会因速度而获胜的原因是:当你调用usecols时,Python将为每个列构建一个字符串对象,并为你构建一个列表。然后你索引列表以获取你需要的一个字符串,Python将销毁列表并销毁它创建的对象(除了你想要的列)。 Python的对象池中的这种“流失”需要一些时间,并且您将该时间乘以文件中的行数。 Pandas可以解析这些行,并只返回Python所需的行,因此它可能会获胜。

但这仅仅是猜测。加快速度的原则是:衡量。运行代码,测量它的速度,然后运行其他代码并测量,看看加速是否值得。

答案 1 :(得分:5)

csv module是读取csv文件的正确方法。生成器可以帮助您在大文件中获得速度和内存使用的正确平衡。

from csv import reader
def getNthCol(filename, n):
  with open(filename) as afile:
    r = reader(afile)
    for line in r:
      yield r[n]

如果您的列号的偏移设置为1,则可能需要将-1调整为-1。

更新

另一种方式几乎肯定不是渐近有效,但可能实际上非常快就是转置文件并获取某一行。

def getNthCol(filename, n):
  with open(filename) as afile:
    return zip(*reader(afile))[n]

答案 2 :(得分:1)

我认为你建议的方法是最好的方法:

def nth_column(filepath, n):
    n -= 1 # since indices starts at 0
    columns = []
    with open(filepath, 'r') as my_file:
        for line in my_file:
            try: columns.append(line.split(',')[n])
            except IndexError: pass # if the line doesn't have n columns
    return columns