1

次の形式のデータがあります。

<abc>  <anything2> <anything3>.
<_901>  <first> <something1>.
<_905>  <second> <something2>.
<_910>  <anything> <something3>.
<_901>  <second> <something4>.
<_905>  <first> <something6>.
<_901>  <third> <something5>.
<_905>  <third> <something7>.

ここで、最初の列に対応するすべての情報と、2 番目の列の (1 番目、2 番目、3 番目) の値をグループ化し、次の形式で集計情報を取得します。

   <abc>  <anything2> <anything3>.
   <_901> <something1> <something4> <something5>.
   <_905> <something6> <something2> <something7>.
   <_910>  <anything> <something3>.

Python辞書を使用してこれを達成しようとしました。しかし、私は2テラバイトのファイルを持っているので. 私のプロシージャはメモリ不足で、非常に非効率的です。これを達成するためのPythonでより高速な方法はありますか。はいの場合、誰かが例を挙げて説明してもらえますか?

4

3 に答える 3

1

まず、unix ツールを使用してデータの並べ替えを試すことができますsort(非常に大きなファイルをうまく処理できます)。次に、同じ 1 番目と 2 番目のフィールドを持つ行が連続ブロックになるため、Python スクリプトを使用してそれらを繰り返し処理し、好みの形式で出力できます。2 番目の列に 1 番目、2 番目、または 3 番目がないデータが必要ない場合の例を以下に示します。

# merger.py
# this python script takes in a file with sorted lines and gives your output
import sys

prevtag = None
data = ['', '', '']
printed = True
for line in sys.stdin:
    fields = line.strip().split()
    if fields[0] != prevtag:
        if not printed:
            print prevtag, ' '.join(data)
            printed = True
        prevtag = fields[0]
        data = ['', '', '']
    if fields[1] == '<first>':
        data[0] = fields[2]
        printed = False
    if fields[1] == '<second>':
        data[1] = fields[2]
        printed = False
    if fields[1] == '<third>':
        data[2] = fields[2]
        printed = False
if not printed:
    print prevtag, ' '.join(data)

これで、の出力をこのスクリプトにパイプして、sort目的を達成できます。

sort <inputfile> | python merger.py

入力:

<abc>  <anything2> <anything3>
<_901>  <first> <something1>
<_905>  <second> <something2>
<_910>  <anything> <something3>
<_901>  <second> <something4>
<_905>  <first> <something6>
<_901>  <third> <something5>
<_905>  <third> <something7>

出力:

<_901> <something1> <something4> <something5>
<_905> <something6> <something2> <something7>
于 2013-10-11T00:50:59.803 に答える
0

これはあなたにいくつかのアイデアを与えるかもしれません。システム プログラマーのためのジェネレーターの秘訣に関する David Beazely の講義からいくつかのものを使用しました。ファイルが大きいため、<something>値を別のファイルに保存しています。それらをリスト/辞書に追加できる場合があります。わからない。毎回ファイルを開いたり、追加したり、閉じたりするのはかなり非効率的だと思いますが、他に何も考えられません。

from __future__ import division, print_function
from StringIO import StringIO
import re
import os
import glob

#for generator details see see http://www.dabeaz.com/generators/

def gen_grep_groups(pat, lines):

    patc = re.compile(pat)
    for line in lines:
        match = patc.search(line)
        if match:
            yield match.groups()

def logme(pairs, ext='.special_list'):
    for name, thing in pairs:
        #there must be a better way than opening and closing each time
        f = open(name + ext,'a')
        f.writelines(thing +'\n')
        f.close()


data = StringIO("""<abc>  <anything2> <anything3>.
<_901>  <first> <something1>.
<_905>  <second> <something2>.
<_910>  <anything> <something3>.
<_901>  <second> <something4>.
<_905>  <first> <something6>.
<_901>  <third> <something5>.
<_905>  <third> <something7>.""")

#for a file use data = open(filename)



pat = r'<(.+?)>\s+<(?:first|second|third)>\s+<(.+?)>'
ext = ".special_list"
#patternc = re.compile(pattern)

for f in glob.glob('*'+ ext):
    os.remove(f) #remove any existing files

pairs = gen_grep_groups(pat,data)
logme(pairs, ext)


for filename in glob.glob('*'+ ext):
    #do what you want in here    
    name = os.path.splitext(filename)[0]
    print(name)
    f = open(filename,'r')    
    print(f.read())
    f.close()
于 2013-10-11T05:15:29.443 に答える
0

このサイズのファイルの場合、複数のパスで読み込むことが適切な場合があります。

まず、行を読み取り、データが存在する行番号 (または、ファイルの位置) と共にキー フィールドを保存します。

pos = {}
filepos = file.tell()
for line in file:
    sline = line.split()
    pos.setdefault(sline[0], []).append(filepos)
    filepos.file.tell() # for the next read

これで、{'': [0], <_901>: [25, 87], ...} のような dict ができました。

これで、辞書を繰り返し処理して実行できます

for key, fileposes in pos.iteritems():
    if len(fileposes) == 1:
        file.seek(fileposes[0])
        print file.readline()
    else:
        outlinedata = []
        for filepos in fileposes:
            file.seek(fileposes[0])
            line = file.readline()
            sline = line.split()
            outlinedata.append(sline[2])
        print key, " ".join(outlinedata)

(しかし、tell/seek一方で、ファイルの行ごとの読み取りとバッファリングが互いに干渉しないかどうかはわかりません...)

于 2013-10-11T05:30:51.147 に答える