2017-03-22 2 views
0

このスクリプトの目標は、テキストファイルでフォルダ全体を取り込み、すべてのファイルの各行を取り込み、すべての一意の行を含むファイルを降順周波数のオーダー。1ギガバイト分のテキストを1つのファイルにまとめて、出現数でソートします。

これは、一意の行を見つけるだけでなく、すべてのファイルに各一意の行がどれくらい頻繁に出現するかを検出します。

このスクリプトでは、多くのテキストを処理する必要があります。つまり、少なくとも2GBほどであるため、効率的に処理する必要があります。 これまでのところ、私はこの目標を達成していません。

import os, sys #needed for looking into a directory 
from sys import argv #allows passing of arguments from command line, where I call the script 
from collections import Counter #allows the lists to be sorted by number of occurrences 

#Pass argument containing Directory of files to be combined 
dir_string = str((argv[1])) 

filenames=[] 

#Get name of files in directory, add them to a list 
for file in os.listdir(dir_string): 
    if file.endswith(".txt"): 
     filenames.append(os.path.join(dir_string, file)) #add names of files to a list 

#Declare name of file to be written 
out_file_name = dir_string+".txt" 

#Create output file 
outfile = open(out_file_name, "w") 

#Declare list to be filled with lines seen 
lines_seen = [] 

#Parse All Lines in all files 
for fname in filenames: #for all files in list 
    with open(fname) as infile: #open a given file 
     for line in infile: #for all lines in current file, read one by one 
       #Here's the problem. 
       lines_seen.append(str(line).strip('\n')) #add line to list of lines seen, 
                 #removing the endline 

    #Organizes the list by number of occurences, but produced a list that contains 
    # [(item a, # of a occurrences), (item b, # of b occurrences)...] 
    lines_seen = Counter(lines_seen).most_common() 

    #Write file line by line to the output file 
    for item in lines_seen: outfile.write(str(item[0])+"\n") 

outfile.close() 

エラーメッセージが表示されたら、それは約lines_seen.append(str(line).strip('\n'))です。

私はまず文字列とストリッピングに変換せずに行を追加しようとしましたが、私に受け入れられない文字列には '\ n'が含まれていました。 小規模なリストの場合、文字列とストリッピングに変換することはあまりにもメモリ課税ではありませんでした。 Linuxではまだ試していません - 私は私のPC上で終了行の文字

を取り除くのより効率的な方法を見つけ出すことができませんでした 、これはこれは私にKilled: 9を与える私のMac上で、MemoryErrorの原因となります。

バイナリに変換し、順序リストをアセンブルしてから変換する必要がありますか? これ以外にどのようにすることができますか?

EDIT - それは私がこれを行うための最善の全体的な方法は明らかになってきたが、UNIXとあった

cd DirectoryWithFiles 
cat *.txt | sort | uniq -c | sort -n -r > wordlist_with_count.txt 
cut -c6- wordlist_with_count.txt > wordlist_sorted.txt 
+1

'List'をメモリに保存するのではなく、なぜあなたの行を一時ファイルに書き込まないのですか? –

+0

これを書いている時点で、リストに入れないでファイルを並べ替える方法がわからず、同じ問題に戻ってくるのですか? – berzerk0

+0

このスレッドに従ってください:http://stackoverflow.com/questions/41315394/ file-size-limit-for-readあなたは2GBまでのファイルを読むことができます –

答えて

-1

あなたの問題は明らかにメモリ不足であるコマンド。

処理中にlines_seenの冗長な行を削除すると、それが役に立ちます。

from collections import Counter 
lines_seen = Counter() 

# in the for loop : 
lines_seen[ lines_seen.append(str(line).strip('\n')) ] += 1 

# at the end: 
for item in lines_seen.most_common(): 
    outfile.write(str(item[0])+"\n") 

EDIT

他のソリューションは、コメントで述べたように、次のようになります。

from collections import Counter 
lines_seen = Counter() 

# get the files names 

for fname in filenames: #for all files in list 
    with open(fname) as infile: #open a given file 
     lines_seen.update(infile.read().split('\n')) 

for item in lines_seen.most_common(): 
    print(item[0], file=outfile) 
+0

コメントは議論の延長ではありません。この会話は[チャットに移動]されています(http://chat.stackoverflow.com/rooms/138799/discussion-on-answer-by-user9123-combine-gigabytes-worth-of-text-into-one-file) 。 –

0

私はこの

import os, sys #needed for looking into a directory 
from sys import argv #allows passing of arguments from command line, where I call the script 
from collections import Counter #allows the lists to be sorted by number of occurrences 

#Pass argument containing Directory of files to be combined 
dir_string = str((argv[1])) 


#Get name of files in directory, add them to a list 
filenames = [] 
for file in os.listdir(dir_string): 
    if file.endswith(".txt"): 
     filenames.append(os.path.join(dir_string, file)) #add names of files to a list 


#Declare name of file to be written 
out_file_name = os.path.join(dir_string, 'out.txt') 


# write all the files to a single file instead of list 
with open(out_file_name, "w") as outfile: 
    for fname in filenames: #for all files in list 
     with open(fname) as infile: #open a given file 
       for line in infile: #for all lines in current file, read one by one 
        outfile.write(line) 

# create a counter object from outfile 
with open(out_file_name, "r") as outfile: 
    c = Counter(outfile) 



print "sorted by line alphabhitically" 
from operator import itemgetter 
print sorted(c.items(),key=itemgetter(0)) 

print "sorted by count" 
print sorted(c.items(), key=itemgetter(1)) 


def index_in_file(unique_line): 
    with open(out_file_name, "r") as outfile: 
     for num, line in enumerate(outfile, 1): 
      if unique_line[0] in line: 
       return num 

print "sorted by apperance of line in the outfile" 
s= sorted(c.items(),key=index_in_file) 
print s 

# Once you decide what kind of sort you want, write the sorted elements into a outfile. 
with open(out_file_name, "w") as outfile: 
    for ss in s: 
     outfile.write(ss[0].rstrip()+':'+str(ss[1])+'\n') 
0
のようにこの問題を解決しているだろう

これは私が他の回答の一つ下のコメントで示唆されたメモリ消費量を削減するアプローチです:line.strip('\n')のみ、各ラインの読み取りの末尾に改行を削除しているので、line.rstrip('\n')はもっとだろうと

lines_seen = collections.Counter() 

for filename in filenames: 
    with open(filename, 'r') as file: 
     for line in file: 
      line = line.strip('\n') 
      if line: 
       lines_seen.update([line]) 

with open(out_file_name, "w") as outfile: 
    for line, count in lines_seen.most_common(): 
     outfile.write('{}, {}\n'.format(line, count)) 

は注意効率的。 line.strip()を使用して先頭と末尾の空白を削除することもできます。可能であればかなりの空白を取り除くことで、メモリ使用量がさらに減少します。

関連する問題