2017-02-01 40 views
11

CSV'yi python'da belleğe yüklemeden bir CSV'ye başlık satırı eklemenin bir yolu var mı? Bir başlık eklemek istediğim 18GB'lık bir CSV var ve gördüğüm tüm yöntemler CSV'yi belleğe yüklemeyi gerektiriyor.CSV yüklenemedi başlık CSV yüklenemedi

+0

DictWriter'ın writeheader yöntemini denediniz mi? (https://docs.python.org/3/library/csv.html) Tam cevabı bilmiyorum, sadece bir fikir: Eğer dosyayı 'a' ile açarsanız ve writeheader'ı kullanmaya çalışırsanız çalışıyor mu? Eğer yanlış bir şey varsa, orijinal dosyanın bir kopyasını deneyerek bunu yapmak iyi olurdu. – Kroy

+0

3 yöntemin hız karşılaştırması için güncellenmiş cevaba bakın. –

cevap

6

Sadece gerçeği kullandıkları satırlarda csv modül yinelediğinden asla writerows çok iyi bir hız sağlamak kullanarak belleğe

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) 

tüm dosyayı yükler böylece. Bellek buradan kurtuldu. Her şey hattan yapılır. Veriler doğru bir şekilde işlendiğinden, ayırıcıyı ve/veya çıktı dosyasındaki alıntıları bile değiştirebilirsiniz.

7

Tüm dosyayı yeniden yazmanız gerekecektir. En basit

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

Python tabanlı çözümler çok daha yüksek düzeylerde çalışacak ve çok yavaş olacaktır Python kullanmak değildir. 18GB, hepsinden sonra çok veri. En hızlı olacak işletim sistemi işlevselliği ile çalışmak daha iyidir.

+0

Python'dan ayrılmak istemiyorsanız, bunu bir 'subprocess.call()' çağrısında her zaman yapabilirsiniz. Hatta Python'daki ilk satırın yazısını da @ maximilian-peters'ın cevabı gibi yapın. –

+0

Bu aslında en hızlı çözümdür, diğer cevaptaki referans noktasına bakın. –

+0

Karşılaştırma yapmak için zaman ayırdığınız için @MaximilianPeters teşekkürler – e4c5

3

Burada 10^6 satır ve 10 sütun (n = 50) olan bir ~ 200 MB CSV dosyası için önerilen üç çözümün bir karşılaştırması. Bu oran, daha büyük ve daha küçük dosyalar için yaklaşık aynı kalır (10 MB - 8 GB).

cp: shutil: yerleşik cp işlevini kullanarak 1:10:55

yani Python'un csv modülü kullanarak yaklaşık olarak 55 kat daha hızlı olduğu csv_reader.

Bilgisayar:

  • düzenli HDD
  • Python 3.5.2 64 bit
  • 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]))) 

gerçekten Python bunu yapmak istiyorsan, önce başlık dosyası oluşturmak ve sonra shutil.copyfileobj üzerinden 2 dosyasıyla birleştirebilir.

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)