0

つまり、4,000個の大きなgzip圧縮されたテキストファイルがあります。サイズが大きいため、1行ずつ合計する必要があります。理想的には(私は思う)1つを開いてから、他の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ます。したがって、出力はカンマで区切られたfloatのリストです(例:)[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分。

4

3 に答える 3

4

通常のPythonの方法で...

あなたは線を繰り返していません...

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

ただし、すべての行を読み取ってから、それらにfloatを適用することはできます。

>>> 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 !

多くのNumPy関数が記述されてCであり、最適化されているため、このソリューションはPierreが提供したソリューションに対してより高速に実行されることに注意してください。4000行で実行する必要がある場合は、forループが遅くなると思います...

于 2012-09-20T12:10:41.360 に答える
2

おそらく、最初のファイルの行を格納するリストを1つメモリに保持する必要があります。

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()])
    

次に、2番目のファイルを開き、その行をループして、次の対応するエントリに値を追加します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. 入力ファイル全体を読み取るまで、別の行のチャンクに対して手順2を繰り返します。

この時点で、foo1定義したチャンクと同じ数のエントリを含むリストが作成されます。各エントリはnumpy配列です。今

  1. 2番目のファイルを開き、手順2で行ったのと同じ数の行を読み取り、これらの行をnumpy配列に変換しますfoo2_tmp
  2. に追加foo2_tmpfoo_1[0]、その場で:つまり、実行しますfoo_1[0] += foo2_tmp。覚えておいてください、foo_1[0]あなたの最初のチャンクndarrayです。
  3. 別の行のチャンクに対して手順5を繰り返し、の対応するエントリを更新します。foo_1
  4. 2番目のファイルを読み取るまで、手順6を繰り返します。
  5. 手順4〜7を繰り返します。3番目のファイル
于 2012-09-20T12:16:16.663 に答える
0

これはテストされていません。一度に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]
于 2012-09-20T12:18:29.517 に答える