如何在一个以制表符分隔的文件中查找列数。

3

我有一个制表符分隔的文件,其中包含10亿行这样的数据(想象一下有200多列而不是3列):

abc -0.123  0.6524  0.325
foo -0.9808 0.874   -0.2341 
bar 0.23123 -0.123124   -0.1232

如果列数未知,如何在制表符分隔的文件中找到列数?
我尝试过以下方法:
import io
with io.open('bigfile', 'r') as fin:
    num_columns = len(fin.readline().split('\t'))

以下是来自@EdChum的答案(从Read a tab separated file with first column as key and the rest as values):

import pandas as pd
num_columns = pd.read_csv('bigfile', sep='\s+', nrows=1).shape[1]  

我还能通过哪些方式获取列数?哪种方法最有效?(想象一下,我突然收到一个未知列数的文件,比如超过100万列)


3
最后的代码片段有什么问题(是我编写的),它只读取一行并输出一个数字? - EdChum
1
或者说,读取文件的第一行并计算列数有什么问题? - Julien Spronck
@EdChum,我只是想确认是否有其他方法来获取列数并对其进行基准测试。 - alvas
好的,请让我知道它是否是最快的,我很想知道pandas的表现如何。 - EdChum
我尝试计时不同的代码,但是pandas给了我一个StopIteration:错误。 - Padraic Cunningham
执行以下命令:awk '{print NF;quit}' file - Mark Setchell
2个回答

2

在一个有100000列的文件中,一些计时结果显示count函数最快,但是结果却少了一列:

In [14]: %%timeit                    
with open("test.csv" ) as f:
    r = csv.reader(f, delimiter="\t")
    len(next(r))
   ....: 
10 loops, best of 3: 88.7 ms per loop

In [15]: %%timeit                    
with open("test.csv" ) as f:
    next(f).count("\t")
   ....: 
100 loops, best of 3: 11.9 ms per loop
with io.open('test.csv', 'r') as fin:
    num_columns = len(next(fin).split('\t'))
    ....: 
 10 loops, best of 3: 133 ms per loop

使用str.translate实际上似乎是最快的,尽管你需要再加1:
In [5]: %%timeit
with open("test.csv" ) as f:
    n = next(f)
    (len(n) - len(n.translate(None, "\t")))
   ...: 
100 loops, best of 3: 9.9 ms per loop

使用pandas的解决方案给我报错:

in pandas.parser.TextReader._read_low_memory (pandas/parser.c:7977)()

StopIteration: 

使用readline会增加额外的开销:

In [19]: %%timeit
with open("test.csv" ) as f:
    f.readline().count("\t")
   ....: 
10 loops, best of 3: 28.9 ms per loop
In [30]: %%timeit
with io.open('test.csv', 'r') as fin:
    num_columns = len(fin.readline().split('\t'))
   ....: 
10 loops, best of 3: 136 ms per loop

Python 3.4 的结果不同:

In [7]: %%timeit
with io.open('test.csv', 'r') as fin:
    num_columns = len(next(fin).split('\t'))
   ...: 
10 loops, best of 3: 102 ms per loop

In [8]: %%timeit
with open("test.csv" ) as f:
    f.readline().count("\t")
   ...: 

100 loops, best of 3: 12.7 ms per loop   
In [9]:     
In [9]: %%timeit
with open("test.csv" ) as f:
    next(f).count("\t")
   ...: 
100 loops, best of 3: 11.5 ms per loop    
In [10]: %%timeit
with io.open('test.csv', 'r') as fin:
    num_columns = len(next(fin).split('\t'))
   ....: 
10 loops, best of 3: 89.9 ms per loop    
In [11]: %%timeit
with io.open('test.csv', 'r') as fin:
    num_columns = len(fin.readline().split('\t'))
   ....: 
10 loops, best of 3: 92.4 ms per loop   
In [13]: %%timeit     
with open("test.csv" ) as f:
    r = csv.reader(f, delimiter="\t")
    len(next(r))
   ....: 
10 loops, best of 3: 176 ms per loop

@alvas,已添加差异,我将在几分钟内添加更多不同的方法。 - Padraic Cunningham
你的pandas解决方案是什么? - EdChum
啊好的,如果你明确地将 low_memory=False 设置为什么会发生? - EdChum
哎呀,那太糟糕了!你使用的是哪个版本的pandas、numpy和python? - EdChum
@EdChum,分别是0.16.0和1.9.2版本,我想pandas处理所有数据时都会调用文件对象或读取器上的next函数,并在第一行/行上进行一次遍历,以便尽可能地减少操作。 - Padraic Cunningham
显示剩余2条评论

0

有一个str.count()方法:

h = file.open('path', 'r')
columns = h.readline().count('\t') + 1
h.close()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接