我有一个几十万行的文件,如下所示:
01,T,None,Red,Big
02,F,None,Purple,Small
03,T,None,Blue,Big
.......
我想要一些可以从整个文件中检索第n列的东西。例如,第 4 列将是:
Red
Purple
Blue
由于文件非常大,我有兴趣知道最有效的方法。
显而易见的解决方案是逐行浏览文件,然后应用 split(',') 并获取数组中的第 4 项,但我想知道是否有更好的方法。
我有一个几十万行的文件,如下所示:
01,T,None,Red,Big
02,F,None,Purple,Small
03,T,None,Blue,Big
.......
我想要一些可以从整个文件中检索第n列的东西。例如,第 4 列将是:
Red
Purple
Blue
由于文件非常大,我有兴趣知道最有效的方法。
显而易见的解决方案是逐行浏览文件,然后应用 split(',') 并获取数组中的第 4 项,但我想知道是否有更好的方法。
我认为您无法仅在读取文件和使用str.split()
. 但是,您还没有向我们展示您的所有代码......您可能需要确保在处理它之前没有将整个文件读入内存(使用file.readlines()
方法 function 或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 对此提供了很好的支持。
嗯,现在我想起来了:您应该尝试使用 Pandas 导入该文本文件。我记得 Pandas 的作者说他写了一些低级代码,大大加快了解析输入文件的速度。
哦,找到了:http ://wesmckinney.com/blog/a-new-high-performance-memory-efficient-file-parser-engine-for-pandas/
唔。查看 Pandas 文档,您似乎可以使用read_csv()
可选参数usecols
来指定您想要的列的子集,它会丢弃其他所有内容。
http://pandas.pydata.org/pandas-docs/stable/generated/pandas.io.parsers.read_csv.html
我认为 Pandas 可能会以速度取胜的原因:当您调用 时line.split(',')
,Python 将为每一列构建一个字符串对象,并为您构建一个列表。然后你索引列表以获取你需要的一个字符串,Python 将销毁列表并销毁它创建的对象(除了你想要的列)。Python 的对象池中的这种“搅动”需要一些时间,然后将该时间乘以文件中的行数。Pandas 可以解析这些行,并仅将您需要的行返回给 Python,因此它可能会获胜。
但这一切都只是猜测。加快速度的规则是:衡量。运行代码,测量它的速度,然后运行其他代码并测量,看看加速是否值得。
csv 模块是读取 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 偏移量一无所知,您可能需要将 n 调整为 -1。
另一种几乎可以肯定渐近效率较低但实际上可能相当快的方法是转置文件并抓取某一行。
def getNthCol(filename, n):
with open(filename) as afile:
return zip(*reader(afile))[n]
我认为您建议的方法是最好的方法:
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