2017-10-20 8 views
3

私はPython初心者で、いくつかの基本的なスクリプトを作成しました。私の最近の課題は、非常に大きなcsvファイル(10GB +)を各行の特定の変数の値に基づいていくつかの小さなファイルに分割することです。Pythonを使用して特定の列に基づいてcsvファイルを分割する

Category,Title,Sales 
"Books","Harry Potter",1441556 
"Books","Lord of the Rings",14251154 
"Series", "Breaking Bad",6246234 
"Books","The Alchemist",12562166 
"Movie","Inception",1573437 

そして、私は別のファイルにファイルを分割したい:

たとえば、ファイルは次のように見えるかもしれ Books.csv、Series.csv、Movie.csv

で現実には数百のカテゴリがあり、分類されません。この場合、彼らは最初の欄にありますが、将来はそうではないかもしれません。

私はいくつかのソリューションをオンラインで見つけましたが、Pythonでは何も見つかりませんでした。これを1行で行うことができる、とてもシンプルなAWKコマンドがありますが、私はAWKにアクセスできません。

私は次のコードを書いていますが、おそらく非常に非効率です。誰もそれをスピードアップする方法を提案することはできますか?

import csv 

#Creates empty set - this will be used to store the values that have already been used 
filelist = set() 

#Opens the large csv file in "read" mode 
with open('//directory/largefile', 'r') as csvfile: 

    #Read the first row of the large file and store the whole row as a string (headerstring) 
    read_rows = csv.reader(csvfile) 
    headerrow = next(read_rows) 
    headerstring=','.join(headerrow) 

    for row in read_rows: 

     #Store the whole row as a string (rowstring) 
     rowstring=','.join(row) 

     #Defines filename as the first entry in the row - This could be made dynamic so that the user inputs a column name to use 
     filename = (row[0]) 

     #This basically makes sure it is not looking at the header row. 
     if filename != "Category": 

      #If the filename is not in the filelist set, add it to the list and create new csv file with header row. 
      if filename not in filelist:  
       filelist.add(filename) 
       with open('//directory/subfiles/' +str(filename)+'.csv','a') as f: 
        f.write(headerstring) 
        f.write("\n") 
        f.close()  
      #If the filename is in the filelist set, append the current row to the existing csv file.  
      else: 
       with open('//directory/subfiles/' +str(filename)+'.csv','a') as f: 
        f.write(rowstring) 
        f.write("\n") 
        f.close() 

ありがとうございます!

+0

なぜ 'pandas'を使わないのですか? – Dadep

答えて

1

メモリを効率的に使用する方法と、ここにファイルを再オープンすることを避ける方法(開いているファイルハンドルを大量に生成しない限り)を使用して、dictを使用してカテゴリをfileobjにマップします。そのファイルがまだ開かれていない場所に作成し、ヘッダを書き込んだら、常にすべての行を対応するファイルに書き込んでください。例:

import csv 

with open('somefile.csv') as fin:  
    csvin = csv.DictReader(fin) 
    # Category -> open file lookup 
    outputs = {} 
    for row in csvin: 
     cat = row['Category'] 
     # Open a new file and write the header 
     if cat not in outputs: 
      fout = open('{}.csv'.format(cat), 'w') 
      dw = csv.DictWriter(fout, fieldnames=csvin.fieldnames) 
      dw.writeheader() 
      outputs[cat] = fout, dw 
     # Always write the row 
     outputs[cat][1].writerow(row) 
    # Close all the files 
    for fout, _ in outputs.values(): 
     fout.close() 
+0

ありがとうございます。私はあなたのソリューションを見た前に何かを思いつきました(元の投稿を見て、私はコードが修正されているので、今すぐ動作します)。 新しいカテゴリであるかどうか、または私のものよりも効率的でないかどうかを確認する方法はありますか? – Actuary

+0

@Actuaryチェックは速くする必要はありませんが、ファイルを開閉しない/開いていないとIOオーバーヘッドが大幅に減少します –

関連する問題