Python中快速读取列数不同的大文件的最佳方法

4

我有一个包含浮点数的数据集,在文件data.txt中,每行包含不同数量的列。例如:

    3.0 2.5
    1.1 30.2 11.5
    5.0 6.2
    12.2 70.2 14.7 3.2 1.1

为了读取它,我可以在Matlab中轻松使用fopenfscanf的组合。最后一个会按列顺序读取并将数据转换为数组,就像这个:
    array = [3.0 2.5 1.1 30.2 11.5 5.0 6.2 12.2 70.2 14.7 3.2 1.1]'

我希望将我的Matlab代码翻译成Python。但是由于Python没有内置函数可以替换Matlab的fscanf,因此我编写了以下Python代码,以相同的方式读取和重塑数据:

    from numpy import *

    data = []
    with open('data.txt') as file:
       for line in file:
          cline = line.split()
          data = data + cline

    data = array(data)

这段代码可以运行,但我的一些数据集可能会有多达 200,000 行,而我展示的 Python 代码对于读取大型数据集(约 10 分钟)来说非常慢。另一方面,Matlab 的 fscanf 只需要几秒钟就可以完成任务。那么,在 Python 中是否有比我的代码更快(优化)的方法来完成这项工作呢?
我真的很感激任何建议。

你也有pandas吗? - cs95
不,我没有pandas。目前我不知道如何在这种情况下使用它。但是我在其中一个答案中找到了解决方案:将data = data + cline替换为data.extend(cline),代码运行时间少于一秒钟。 - Carlos Herrera
3个回答

2

在几千行之后,这个程序需要做大量的额外工作:

    data = data + cline

只需要使用 data.extend(cline)。(或者使用 .append(),如果你想知道哪些数字在同一行出现。)

考虑存储双精度数而不是文本:

    data.extend([float(c) for c in line.split()])

好的观点。实际上,“data += cline”就可以完成任务。 - Jean-François Fabre
1
非常感谢!应用了这个修复后,代码运行时间不到一秒。 - Carlos Herrera

2

numpy.loadtxt在这里本来是完美的选择,但由于列数会改变,所以不适用。

如果你想要一个扁平化的列表,你可以使用列表推导式来加快速度:

from numpy import *
with open("file.txt") as f:
    data = array([float(x) for l in f for x in l.split()])

现在我非常确信,考虑到JH在他的回答中指出的错误,速度会更快:每次data = data + line都会创建一个新列表:二次复杂度。您可以通过列表理解来避免这种情况。


2

Pandas在处理不规则列方面比numpy更好/更快,并且应该比使用循环的纯Python实现更快。

使用read_csv,然后是stack,最后访问values属性以返回一个numpy数组。

max_per_row = 10 # set this to the max possible number of elements in a row

vals = pd.read_csv(buf, header=None, names=range(max_per_row),
                             delim_whitespace=True).stack().values

print(vals)
array([  3. ,   2.5,   1.1,  30.2,  11.5,   5. ,   6.2,  12.2,  70.2,
        14.7,   3.2,   1.1])

我刚刚安装了pandas并测试了这段代码。是的!它的速度和其他Python实现一样快。从现在开始,我会记住两种方法。 - Carlos Herrera

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