【问题标题】:The fastest way to read input in Python在 Python 中读取输入的最快方法
【发布时间】:2013-02-12 07:49:40
【问题描述】:

我想读取一个包含整数列表的巨大文本文件。 现在我正在执行以下操作:

G = []
with open("test.txt", 'r') as f:
    for line in f:
        G.append(list(map(int,line.split())))

但是,大约需要 17 秒(通过 timeit)。有什么办法可以减少这个时间吗?也许,有办法不使用地图。

【问题讨论】:

  • 尝试列表理解。
  • 这里有什么不使用numpy的理由吗?
  • 定义“巨大”。另外,每一行的整数个数是否相同?
  • @WarrenWeckesser 实际上在这个例子中有相同数量的整数,两个元素。巨大的 > 5M 行。

标签: python input python-3.x readfile


【解决方案1】:

numpy 有函数loadtxtgenfromtxt,但都不是特别快。在广泛分布的库中可用的最快的文本阅读器之一是pandas (http://pandas.pydata.org/) 中的read_csv 函数。在我的电脑上,读取 500 万行,每行包含两个整数,numpy.loadtxt 需要大约 46 秒,numpy.genfromtxt 需要 26 秒,pandas.read_csv 需要 1 秒多一点。

这是显示结果的会话。 (这是在 Linux 上,Ubuntu 12.04 64 位。你在这里看不到它,但是在每次读取文件后,通过在单独的 shell 中运行 sync; echo 3 > /proc/sys/vm/drop_caches 来清除磁盘缓存。)

In [1]: import pandas as pd

In [2]: %timeit -n1 -r1 loadtxt('junk.dat')
1 loops, best of 1: 46.4 s per loop

In [3]: %timeit -n1 -r1 genfromtxt('junk.dat')
1 loops, best of 1: 26 s per loop

In [4]: %timeit -n1 -r1 pd.read_csv('junk.dat', sep=' ', header=None)
1 loops, best of 1: 1.12 s per loop

【讨论】:

  • +1,我在准备我的时候没有看到你的答案。我也刚刚对 OP 的版本进行了基准测试,这在我的机器上大约需要 16 秒。我还注意到,loadtxt 很慢。我不知道为什么,我希望它会更快(它应该比genfromtxt 更快。你也使用 numpy 1.7 吗?
  • @bmu:是的,我用的是 numpy 1.7。
  • 我打开了一个 numpy 问题:github.com/numpy/numpy/issues/3019。我无法想象,loadtxt 这么慢是正常的。
  • @BranAlgue:Christoph Gohlke 通过为 Windows 准备和托管 NumPy(和许多其他包)的二进制构建,为 Python 社区提供了巨大的服务。看一看:lfd.uci.edu/~gohlke/pythonlibs/#numpy
  • 嘿,@WarrenWeckesser 它有帮助。它读取文件但花了大约一分钟时间,并且数字是浮点类型,这是不对的。不幸的是,没有适用于 Python 3.3 的 pandas。也许要在 3.2 上重新安装?
【解决方案2】:

基于numpypandas 有一个基于file parserC,速度非常快:

# generate some integer data (5 M rows, two cols) and write it to file
In [24]: data = np.random.randint(1000, size=(5 * 10**6, 2))

In [25]: np.savetxt('testfile.txt', data, delimiter=' ', fmt='%d')

# your way
In [26]: def your_way(filename):
   ...:     G = []
   ...:     with open(filename, 'r') as f:
   ...:         for line in f:
   ...:             G.append(list(map(int, line.split(','))))
   ...:     return G        
   ...: 

In [26]: %timeit your_way('testfile.txt', ' ')
1 loops, best of 3: 16.2 s per loop

In [27]: %timeit pd.read_csv('testfile.txt', delimiter=' ', dtype=int)
1 loops, best of 3: 1.57 s per loop

所以pandas.read_csv 需要大约一秒半的时间来读取您的数据,并且比您的方法快大约 10 倍。

【讨论】:

    【解决方案3】:

    作为一般经验法则(几乎适用于任何语言),使用read() 读取整个文件比一次读取一行要快。如果您不受内存限制,请立即读取整个文件,然后在换行符上拆分数据,然后遍历行列表。

    【讨论】:

      【解决方案4】:

      您也可以尝试通过批量插入将数据导入数据库,然后使用集合操作处理您的记录。根据您必须执行的操作,这可能会更快,因为批量插入软件已针对此类任务进行了优化。

      【讨论】:

        【解决方案5】:

        列表推导通常更快。

        G = [[int(item) item in line.split()] for line in f]
        

        除此之外,试试 PyPy 和 Cython 和 numpy

        【讨论】:

        • G = [map(int, line.split()) for line in f] 更快。
        • @StevenRumbalski 此行生成地图对象:[<map object at 0x0000000002D28898>, <map object at 0x0000000002D28908>, <map object at 0x0000000002D289B0>...。但是@forivall 行有效。
        • @BranAlgue。啊哈!您使用的是 Python 3。因此将其更改为 G = [list(map(int, line.split())) for line in f]。它仍然比嵌套列表理解要快。
        • 这很奇怪@StevenRumbalski,因为您的线路运行缓慢:stmt = ''' with open("SCC.txt", 'r') as f: G = [list(map(int, line.split())) for line in f] ''' test1 = timeit.timeit(stmt, number = 1) stmt = ''' with open("SCC.txt", 'r') as f: G = [[int(item) for item in line.split()] for line in f] ''' test2 = timeit.timeit(stmt, number = 1)>>> test1 16.291107619840908 >>> test2 11.386214308615607
        • Python 3 的更改可能提高了 listcomps 的性能。概述此问题的旧问题:stackoverflow.com/questions/1247486/…
        【解决方案6】:

        最简单的加速方法是使用 PyPy http://pypy.org/

        下一个根本不读取文件的问题(如果可能的话)。而是像流一样处理它。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-24
          • 2018-12-11
          • 1970-01-01
          • 2014-03-20
          • 1970-01-01
          • 2014-09-26
          相关资源
          最近更新 更多