2017-02-01 5 views
11

CSVにヘッダ行を追加する方法はありますか?私はヘッダーを追加する18GBのCSVを持っています。私が見たすべての方法では、CSVをメモリに読み込む必要がありますが、これは明らかに実行不可能です。CSVをロードせずにCSVにヘッダを追加

+0

DictWriterの書き込みヘッドメソッドを試しましたか? (https://docs.python.org/3/library/csv.html) 正確な答えはわかりませんが、ちょっとしたアイデア:「a」でファイルを開いてwriteheaderを使用しようとすると、それは動作しますか? 何か問題がある場合は、元のファイルのコピーを試してみるとよいでしょう。 – Kroy

+0

3つの方法の速度比較については、更新された回答を参照してください。 –

答えて

6

だけで、行にそのcsvモジュールを反復事実を使用しています。メモリはここで節約されます。すべてが行単位で行われます。データが適切に処理されるので、セパレータや出力ファイルの引用符を変更することさえできます。

7

ファイル全体を書き直す必要があります。最も単純なのはPythonを使用しないことです

echo 'col1, col2, col2,... ' > out.csv 
cat in.csv >> out.csv 

Pythonベースのソリューションははるかに高いレベルで動作し、非常に遅くなります。結局、18GBは大量のデータです。オペレーティングシステムの機能を使用する方が良いでしょう。それは非常に良いスピードを確保writerowsを使用してメモリに

import csv 

with open("huge_csv.csv") as fr, open("huge_output.csv","w",newline='') as fw: 
    cr = csv.reader(fr) 
    cw = csv.writer(fw) 
    cw.writerow(["title1","title2","title3"]) 
    cw.writerows(cr) 

をファイル全体をロードしたことがないので、

+0

そして、Pythonを離れたくないなら、いつでも 'subprocess.call()'呼び出しでこれをラップすることができます。あるいは、@ maximilian-petersの答えのように、Pythonの最初の行を書くことさえできます。 –

+0

これは実際には最も速い解決策です。他の答えのベンチマークを参照してください。 –

+0

@MaximilianPetersに時間を割いて比較していただきありがとうございます – e4c5

3

ここでは、10^6行と10個の列(n = 50)の〜200 MBのCSVファイルに対する3つの推奨ソリューションの比較を示します。 大小のファイル(10 MB〜8 GB)の比率はほぼ同じです。

CP:shutil:1時10分55秒

すなわちcsv_reader組み込みcp関数を使用して、Pythonのcsvモジュールを使用するよりも約55倍高速です。

コンピュータ:

  • 通常のHDD
  • のPython 3.5.2 64ビット
  • のUbuntu 16.04
  • i7-3770

enter image description here


import csv 
import random 
import shutil 
import time 
import subprocess 

rows = 1 * 10**3 
cols = 10 
repeats = 50 

shell_script = '/tmp/csv.sh' 
input_csv = '/tmp/temp.csv' 
output_csv = '/tmp/huge_output.csv' 
col_titles = ['titles_' + str(i) for i in range(cols)] 

with open(shell_script, 'w') as f: 
    f.write("#!/bin/bash\necho '{0}' > {1}\ncat {2} >> {1}".format(','.join(col_titles), output_csv, input_csv)) 

with open(shell_script, 'w') as f: 
    f.write("echo '{0}' > {1}\ncat {2} >> {1}".format(','.join(col_titles), output_csv, input_csv)) 
subprocess.call(['chmod', '+x', shell_script]) 

run_times = dict([ 
    ('csv_writer', list()), 
    ('external', list()), 
    ('shutil', list()) 
]) 

def random_csv(): 
    with open(input_csv, 'w') as csvfile: 
     csv_writer = csv.writer(csvfile, delimiter=',') 
     for i in range(rows): 
      csv_writer.writerow([str(random.random()) for i in range(cols)]) 
    with open(output_csv, 'w'): 
     pass 

for r in range(repeats): 
    random_csv() 
    #http://stackoverflow.com/a/41982368/2776376 
    start_time = time.time() 
    with open(input_csv) as fr, open(output_csv, "w", newline='') as fw: 
     cr = csv.reader(fr) 
     cw = csv.writer(fw) 
     cw.writerow(col_titles) 
     cw.writerows(cr) 
    run_times['csv_writer'].append(time.time() - start_time) 

    random_csv() 
    #http://stackoverflow.com/a/41982383/2776376 
    start_time = time.time() 
    subprocess.call(['bash', shell_script]) 
    run_times['external'].append(time.time() - start_time) 

    random_csv() 
    #http://stackoverflow.com/a/41982383/2776376 
    start_time = time.time() 
    with open('header.txt', 'w') as header_file: 
     header_file.write(','.join(col_titles)) 

    with open(output_csv, 'w') as new_file: 
     with open('header.txt', 'r') as header_file, open(input_csv, 'r') as main_file: 
      shutil.copyfileobj(header_file, new_file) 
      shutil.copyfileobj(main_file, new_file) 
    run_times['shutil'].append(time.time() - start_time) 

    print('#'*20) 
    for key in run_times: 
     print('{0}: {1:.2f} seconds'.format(key, run_times[key][-1])) 

print('#'*20) 
print('Averages') 
for key in run_times: 
    print('{0}: {1:.2f} seconds'.format(key, sum(run_times[key])/len(run_times[key]))) 

あなたが本当にPythonでそれをしたい場合は、最初にヘッダファイルを作成し、shutil.copyfileobjを経由して2回目の自分のファイルにマージできます。

import shutil 
with open('header.txt', 'w') as header_file: 
    header_file.write('col1;col2;col3') 

with open('new_file.csv', 'w') as new_file: 
    with open('header.txt', 'r') as header_file, open('main.csv', 'r') as main_file: 
     shutil.copyfileobj(header_file, new_file) 
     shutil.copyfileobj(main_file, new_file) 
関連する問題