0

まず、SO に関する Python メモリ エラーの質問の量を認識していますが、これまでのところ、私のユース ケースに一致するものはありません。

現在、一連のテキストファイル(〜30 GBの〜6kファイル)を解析し、一意の単語をそれぞれ保存しようとしています。はい、単語リストを作成しています。いいえ、悪いことをするつもりはありません。大学用です。

見つかった単語のリストをセットとして実装しました ( で作成されwords = set([])、 で使用されwords.add(word)ます)。セットの仕組みがすべての重複を削除する必要があることを考慮して、見つかったすべての単語をそれに追加するだけです。

これは、これが機能するためにセット全体に永続的にアクセスする必要があることを意味します (または、挿入ごとにリスト全体の重複をチェックする必要があるため、少なくとも代替手段はありません)。

現在、MemoryError約 3.4 GB の RAM を使用している場合、約 25% に達しています。私は Linux 32 ビットを使用しているので、その制限がどこから来るのかを知っています。また、私の PC には 4 ギガの RAM しかないため、64 ビットでもここでは役に立ちません。

複雑さはおそらくひどいことを知っています(Pythonセットがどのように実装されているか(ツリー?)はわかりませんが、各挿入でおそらくO(n))が、それでも(おそらく)高速で(間違いなく)メモリ効率が高くなります各単語をプリミティブ リストに追加し、後で重複を削除するよりも。

これを実行する方法はありますか?約 6 ~ 10 GB の一意の単語が予想されるため、現在の RAM を使用することは問題外であり、RAM をアップグレードすることは現在不可能です (また、このスクリプトを大量のファイルに解放し始めると、あまりうまくスケーリングしません)。 .

現時点での私の唯一のアイデアは、ディスクにキャッシュすることです(これによりプロセスがさらに遅くなります)、または一時的なセットをディスクに書き込んで後でそれらをマージすることです。これにはさらに時間がかかり、複雑さは確かに恐ろしいものになります。ひどいランタイムにならない解決策さえありますか?

記録のために、これは私の完全な情報源です。個人的な使用のみを目的として書かれたものなので、かなりひどいですが、アイデアはわかります。

import os
import sys
words=set([])
lastperc = 0
current = 1
argl = 0
print "Searching for .txt-Files..."
for _,_,f in os.walk("."):
    for file in f:
        if file.endswith(".txt"):
            argl=argl+1
print "Found " + str(argl) + " Files. Beginning parsing process..."
print "0%                                              50%                                             100%"
for r,_,f in os.walk("."):
    for file in f:
        if file.endswith(".txt"):
            fobj = open(os.path.join(r,file),"r")
            for line in fobj:
                line = line.strip()
                word, sep, remains = line.partition(" ")
                if word != "":
                    words.add(word)
                word, sep, remains = remains.partition(" ")
                while sep != "":
                    words.add(word)
                    word, sep, remains2 = remains.partition(" ")
                    remains = remains2
                if remains != "":
                    words.add(remains)
            newperc = int(float(current)/argl*100)
            if newperc-lastperc > 0:
                for i in range(newperc-lastperc):
                    sys.stdout.write("=")
                    sys.stdout.flush()
            lastperc = newperc
            current = current+1
print ""
print "Done. Set contains " + str(len(words)) + " different words. Sorting..."
sorteddic = sorted(words, key=str.lower)
print "Sorted. Writing to File"
print "0%                                              50%                                             100%"
lastperc = 0
current = 1
sdicl = len(sorteddic)-1
fobj = open(sys.argv[1],"w")
for element in sorteddic:
    fobj.write(element+"\n")
    newperc = int(float(current)/sdicl*100)
    if newperc-lastperc > 0:
        for i in range(newperc-lastperc):
            sys.stdout.write("=")
            sys.stdout.flush()
    lastperc = newperc
    current = current+1
print ""
print "Done. Enjoy your wordlist."

あなたの助けとアイデアをありがとう。

4

5 に答える 5

3

You're probably going to need to store the keys on disk. A key-value store like Redis might fit the bill.

于 2012-06-06T15:08:22.513 に答える
2

あなたは本当に6-10GBのユニークな言葉を意味しますか?これは英語のテキストですか?確かに、適切な名詞と名前を数えても、数百万を超える固有の単語があってはなりません。

とにかく、私がすることは、一度に1つのファイル、または一度にファイルの1つのセクション(たとえば、100k)を処理し、その部分だけに固有のワードリストを作成することです。次に、後処理ステップとしてすべてのセットを結合します。

于 2012-06-06T15:08:42.177 に答える
1

私の傾向はデータベーステーブルにありますが、単一のフレームワーク内にとどまりたい場合は、PyTablesをチェックアウトしてください:http ://www.pytables.org/moin

于 2012-06-06T15:11:46.797 に答える
1

私が最初に試みたのは、単語を小文字に制限することです。Tyler Eaves が指摘したように、これにより、メモリに収まるのに十分なセット サイズが削減される可能性があります。これを行うための非常に基本的なコードを次に示します。

import os
import fnmatch
import re

def find_files(path, pattern):
    for root, files, directories in os.walk(path):
        for f in fnmatch.filter(files, pattern):
            yield os.path.join(root, f)

words = set()
for file_name in find_files(".", "*.txt"):
    with open(file_name) as f:
        data = f.read()
    words.update(re.findall("\w+", data.lower()))

さらにいくつかのコメント:

  1. 私は通常、最初は辞書が急速に成長することを期待しています。プロセスの後半で新しい単語が見つかることはほとんどないため、外挿によって単語リストの最終的なサイズが大幅に過大評価される可能性があります。

  2. この目的には、セットが非常に効率的です。それらはハッシュ テーブルとして実装され、新しい単語を追加すると、償却後の複雑さが O(1) になります。

于 2012-06-06T16:04:31.913 に答える
0

より小さく、より管理しやすいコードスペースにキーをハッシュします。そのハッシュを持つキーを含むファイルにハッシュをキーイングします。ハッシュのテーブルははるかに小さく、個々のキーファイルははるかに小さくなっています。

于 2012-06-06T15:25:54.987 に答える