【问题标题】:Sum two text files containing floats row by row in python在python中逐行求和两个包含浮点数的文本文件
【发布时间】:2012-09-21 18:03:57
【问题描述】:

所以我有 4,000 个大型 gzip 文本文件。由于它们的大小,我需要逐行总结它们。理想情况下(我认为)我想打开一个,然后循环遍历其他 3,999 个,然后简单地将它们的值相加到第一个中。这是我到目前为止所拥有的

with gzip.open('foo1.asc.gz','r') as f:
    for i in xrange(6):  # Header is 6 lines
        f.next()
    line = f.readline()
    foo1=map(float, line.strip().split())
    print foo1

这将返回我需要为 foo1 求和的值;所以输出是一个逗号分隔的浮点数列表(例如,[1.2, 6.0, 9.3...])。

所以为了清楚起见,如果我对foo2 = [1.2, 6.0...] 做同样的事情,那么我可以将foo1foo2 相加得到[2.4, 12.0...],覆盖foo1。然后继续遍历每一行以覆盖foo1。当然,这需要遍历 4k 文件。

如果有人可以帮助我完成 2 个循环和/或求和运算,我将不胜感激。

* 更新 * 现在使用以下代码:

foo1=[]
with gzip.open('foo1','r') as f:
    skip_header()
    for line in f:
        foo1.append([float(i) for i in line.strip().split()])


with gzip.open('foo2','r') as f:
    skip_header()
    for (i, line) in enumerate(f):
        foo1[i] = [j + float(k) for (j, k) in zip(foo1[i], line.strip().split())]

这可行,但很慢。我的输入大约需要 11 分钟。

【问题讨论】:

  • 一个文件有多少个浮点数?
  • 数千...未压缩的文本文件 = 1.3gb
  • 预期的输出是什么?例如,如果 foo1、foo2 文件都包含 "1 2\n3 4",那么结果是 "2 4\n6 8" 还是应该只是 "20"
  • @J.F.Sebastian if foo1 and foo2 = [1.0,2.0,3.0] then output should = [2.0,4.0,6.0]
  • KennyC:你的文件真的使用这种格式[1.0,2.0,3.0]吗?不要转换为列表。按原样提供至少两行(想象一下zcat foo1 | head -2 会显示什么)。

标签: python text gzip sum text-files


【解决方案1】:

以正常的python方式...

您没有遍历这些行...

~ $ cat test.txt 
1.0
2.0
3.0
4.5
5.0
6.0

但是,您可以阅读所有行,然后对其应用浮点数:

>>> with open('test.txt', 'r') as f:
...      lines = f.readlines()
...      foo1=map(float, lines)
...      print foo1
... 
[1.0, 2.0, 3.0, 4.5, 5.0, 6.0]
>>> sum(foo1)
21.5

但是,您应该使用 NumPy!

汇总所有文件的粗略解决方案
import numpy as np

totalsum=0
ListofFiles = ['foo1','foo2']
# from the help of np.loadtxt
# Note that `If the filename extension is .gz or .bz2, the file is first decompressed`
# see the help for that function.
for FileName in ListofFiles:
    totalsum=totalsum+np.sum(np.loadtxt(FileName,skiprows=6))
对来自不同文件的元素求和的解决方案
# use with caution it might hog your memory
import numpy as np

totalsum=0
ListofFiles = ['foo1','foo2']

arrayHolder = np.loadtxt(FileName,skiprows=6)
for idx,FileName in enumerate(ListofFiles[1:]):
    arrayHolder=np.hstack((arrayHolder,np.loadtxt(FileName,skiprows=6)))  
# see documentation for numpy.hstack and my example below.

# now you have a huge numpy array. you can do many things on it
# e.g
# sum each file if the above test.txt had an identical file named test1.txt
np.sum(arrayHolder , axis=0)
# output would be:
array([2.0, 4.0, 6.0, 9.0, 10.0, 12.0])
# sum each ith element accross files
np.sum(arrayHolder , axis=1)

# more extended
In [2]: a=np.array([1.0,2.0,3.0,4.5,5.0,6.0])
In [4]: b=np.array([1.0,2.0,3.0,4.5,5.0,6.0]) 
In [9]: c=np.vstack((a,b))  
In [10]: c
Out[10]:
array([[ 1. , 2. , 3. , 4.5, 5. , 6. ],
[ 1. , 2. , 3. , 4.5, 5. , 6. ]])
In [11]: np.sum(c, axis=0)
Out[11]: array([ 2., 4., 6., 9., 10., 12.])
In [12]: np.sum(c, axis=1)
Out[12]: array([ 21.5, 21.5])

# as I said above this could chocke your memory, so do it gradualy, 
# dont try on all 4000 files at once !

请注意,对于 Pierre 提供的解决方案,此解决方案将运行得更快,因为许多 NumPy 函数是编写的,并且是 C 和优化的。如果您需要在 4000 行上运行,我希望 for 循环会更慢...

【讨论】:

  • 嗨,奥兹,感谢您的帮助。我确实想要一个优化的解决方案,numpy 会很有趣。但也许我应该重申我的问题。我不希望 1 个文件中的浮点数总和。我需要将 2 个文件的浮点数相加。富1+富2。由于文件的大小,我想逐行执行此操作
  • @KennyC,我的解决方案确实为您提供了 foo1foo2 的总和...只需输入 ListOfFiles...
  • 我现在看到了,但是您能否提供一个 numpy 解决方案,将 foo1 的第 1 行与 foo2 的第 1 行相加得到一个浮点数组(例如 foo3 的第 1 行)。 Piere GMs 的解决方案确实有效,但一次操作需要 11 分钟,而我需要一个月才能完成工作。
  • @KennyC,好吧。根据你写的,我是一个懒惰的程序员。我现在扩展我的答案,我认为 Pierre 解决方案不是要走的路,特别是如果它需要一个月才能运行!
  • @KennyC,你可以去掉sir的标题(应该给Travis Oliphant...)。只是出于好奇,快多少?您在一个周期需要 11 分钟之前编写,那么使用 NumPy 需要多少时间?
【解决方案2】:

您可能必须在内存中保留一个列表,该列表存储您的第一个文件的行。

with gzip.open(...) as f:
    skip_header()
    foo1 = [[float(i) for i in line.strip().split()] for line in f]
  • 注意:这里,我们是一次构建列表,这意味着f 的全部内容被加载到内存中。如果文件很大,这可能是一个问题。在这种情况下,只需这样做:

    foo1 = []
    with gzip.open(...) as f:
        skip_header()
        for line in f:
            foo1.append([float(i) for i in line.strip().split()])
    

然后,您可以打开第二个文件,循环其行并将值添加到 foo 的相应条目:

with gzip.open(file2) as f:
    skip_header()
    for (i, line) in enumerate(f):
        foo1[i] = [j + float(k) for (j, k) in zip(foo1[i], line.strip().split())]

应该没有太大问题,除非您的文件中有不同数量的列。

如果您的文件非常大,内存可能是个问题。在这种情况下,您可能希望按块工作:从第一个文件中只读取几百行并将它们存储在一个列表中,然后按照说明进行操作,使用与您在第一个文件中读取的一样多的行,然后重新开始还有几百行……

编辑

考虑到您在编辑中描述的计算时间,这个解决方案显然不是最佳的。您无法将整个文件加载到内存中,因此您必须按块工作。遵循以下工作流程可能会更好:

  1. 创建一个空列表foo1
  2. 打开第一个文件,读取给定的行块,将这些行转换为 numpy ndarray 并将此数组附加到 foo1
  3. 对另一行代码重复第二步,直到读完整个输入文件

此时,您应该有一个 foo1 列表,其中包含与您定义的块一样多的条目,每个条目都是一个 numpy 数组。现在

  1. 打开第二个文件,读取与步骤 #2 中一样多的行,将这些行转换为 numpy 数组 foo2_tmp
  2. foo2_tmp添加到foo_1[0]就地:即做foo_1[0] += foo2_tmp。请记住,foo_1[0] 是您的第一个块,ndarray
  3. 对另一块行重复步骤 5,并更新 foo_1 中的相应条目
  4. 重复第 6 步。直到您读取第二个文件
  5. 重复步骤 4.-7。第三个文件

【讨论】:

  • 我的列和行对于所有输入都是相同的。但是,在执行您的建议时,我在您的第一个块中的 foo1= 行上出现内存错误。想法?
  • 我已编辑 OP 以显示您的建议。我现在收到 I/O 错误
  • @KennyC:新OP的foo1.append(...)行有点不对,请查收。不过,您可以尝试使用list(...) 来强制复制。否则,对不起,我不明白为什么IOError...
  • 谢谢。如果我在您发布时逐字使用有问题的行foo1.append:我得到NameError: name 'line' is not defined
  • 感谢您的所有帮助。我认为这是问题所在,并尝试了 for 循环。不幸的是,使用foo.append 方法我仍然遇到内存错误。不过再次感谢。
【解决方案3】:

这是未经测试的。请注意,尝试一次打开 4,000 个文件句柄可能效率低下(甚至可能不允许),因此一次打开文件的方法是最实用的。下面使用了defaultdict,它允许每个文件中的行数不匹配,但仍然可以对重叠的行数求和。

from itertools import islice
from collections import defaultdict
from glob import iglob

def sum_file(filename, dd):
    file_total = 0.0
    with gzip.open(filename) as fin:
        for lineno, line in enumerate(islice(fin, 6, None)): # skip headers
            row_total = map(float, line.split())                
            dd[lineno] += row_total
            file_total += row_total
    return file_total


dd = defaultdict(float)
for filename in iglob('foo*.asc.gz'):
    print 'processed', filename, 'which had a total of', sum_file(filename, dd)

print 'There were', len(dd), 'rows in total'
for lineno in sorted(dd.keys()):
    print lineno, 'had a total of', dd[lineno]

【讨论】:

  • 是的,对于大量数据,您的解决方案以及 Pierre 的解决方案都会非常缓慢。我会在这里认真使用 NumPy。
  • @Oz123 我认为我们对这个问题的解释不同。我读过它,因为将有 1..n 个元素的总和,其中 nmax(number_of_rows),其中 sum[n] = file1..4000 的行 [1] 的所有列的总和
  • OP已添加信息,他的数据大小为1.3GB...我认为无论哪种方式,4000行或4000个文件,numpy都会更快,将每个文件中的所有浮点数相加并在所有文件中。
  • @Oz123:NumPy 肯定更快,前提是您可以在内存中容纳两个数组。如果没有,你就卡住了。
猜你喜欢
  • 1970-01-01
  • 2014-07-15
  • 1970-01-01
  • 1970-01-01
  • 2014-06-26
  • 1970-01-01
  • 1970-01-01
  • 2021-02-13
  • 1970-01-01
相关资源
最近更新 更多