2015-01-08 4 views
2

Существует большой файл CSV (с первой строкой в ​​виде заголовка), теперь я хочу попробовать его в 100 штук (например, line_num%100), как это сделать эффективно с помощью основного ограничение памяти?как пробовать очень большой файл CSV (6 ГБ)

Отделите файл на 100 меньших единиц. Или каждую 1/100-ю строку в качестве подфайла 1, каждые 2/100-й строки в качестве подфайла 2, ..., каждые 100/100-й строки в виде файла 100. , чтобы получить 100 файлы размером около 600 M.

Не получите 100 строк или образец 1/100.

Я пытался выполнить так:

fi = [open('split_data//%d.csv'%i,'w') for i in range(100)] 
i = 0 
with open('data//train.csv') as fin: 
    first = fin.readline() 
    for line in fin: 
     fi[i%100].write(line) 
     i = i + 1 
for i in range(100): 
    fi[i].close() 

Но файл слишком большой, чтобы запустить его с ограниченным объемом памяти, как с этим бороться? Я хочу сделать это с одного раунда ~

(Мой код работает, но он потребляет слишком много времени, и я ошибочно думал, что это разрушилось, жаль, что ~~)

+1

Вы хотите только прочитать каждую 1/100-ю строку? – ErikR

+0

Я обновил свой ответ (в случае, если вы не просмотрели его через некоторое время.) – ErikR

ответ

6

Чтобы разбить файл на 100 частей, как указано в комментариях (Я хочу разбить файл на 100 частей по модулю, т. е. диапазон (200) -> | [0,100]; [1,101]; [2,102] и Да, отделяйте большую от одной до сотни файлы меньшего размера)

import csv 

files = [open('part_{}'.format(n), 'wb') for n in xrange(100)] 
csvouts = [csv.writer(f) for f in files] 
with open('yourcsv') as fin: 
    csvin = csv.reader(fin) 
    next(csvin, None) # Skip header 
    for rowno, row in enumerate(csvin): 
     csvouts[rowno % 100].writerow(row) 

for f in files: 
    f.close() 

Вы можете islice над файлом с шагом вместо modulus'ing номер строки, например:

import csv 
from itertools import islice 

with open('yourcsv') as fin: 
    csvin = csv.reader(fin) 
    # Skip header, and then return every 100th until file ends 
    for line in islice(csvin, 1, None, 100): 
     # do something with line 

Пример:

r = xrange(1000) 
res = list(islice(r, 1, None, 100)) 
# [1, 101, 201, 301, 401, 501, 601, 701, 801, 901] 
+0

, поэтому, если я хочу получить сто образцов, ему нужно запустить такой большой цикл, как этот 'for i in range (100) # Ваш код с другим индексом в islice # ' ? Так что я должен получить доступ к файлу сто раз? – ling

+0

@ling извините - я не понимаю - не могли бы вы уточнить? –

+0

Я хочу получить сто образцов необработанных данных за один раунд ... – ling

1

на основе @ Джон Клементс ответ, я бы также бенчмарк это изменение:

import csv 
from itertools import islice 

with open('in.csv') as fin: 
    first = fin.readline() # discard the header 
    csvin = csv.reader(islice(fin, None, None, 100)) # this line is the only difference 
    for row in csvin: 
    print row # do something with row 

Если вы хотите только 100 образцов, вы можете использовать эту идею, которая только делает 100 читает в равноудаленных местах с в файле. Это должно хорошо работать для файлов CSV, длина линий которых по существу одинаковая.

def sample100(path): 
    with open(path) as fin: 
    end = os.fstat(fin.fileno()).st_size 
    fin.readline()    # skip the first line 
    start = fin.tell() 
    step = (end - start)/100 
    offset = start 
    while offset < end: 
     fin.seek(offset) 
     fin.readline()   # this might not be a complete line 
     if fin.tell() < end: 
     yield fin.readline() # this is a complete non-empty line 
     else: 
     break     # not really necessary... 
     offset = offset + step 

for row in csv.reader(sample100('in.csv')): 
    # do something with row 
0

Я думаю, вы можете просто открыть тот же самый файл в 10 раз, а затем манипулировать (чтение) каждый из них независимо друг от друга эффективно расщепляя его на суб-файл фактически не делают.

К сожалению, для этого необходимо заранее знать, сколько строк в файле, и что нужно прочитывать все это раз, чтобы подсчитать их. С другой стороны, это должно быть относительно быстрым, поскольку никакой другой обработки не происходит.

Для иллюстрации и проверить этот подход, который я создал простой — только один элемент в строке — и гораздо меньший тест CSV-файл, который выглядел примерно так (первая строка строка заголовка и не учитываются):

line_no 
1 
2 
3 
4 
5 
... 
9995 
9996 
9997 
9998 
9999 
10000 

Вот код и пример вывода:

from collections import deque 
import csv 

# count number of rows in csv file 
# (this requires reading the whole file) 
file_name = 'mycsvfile.csv' 
with open(file_name, 'rb') as csv_file: 
    for num_rows, _ in enumerate(csv.reader(csv_file)): pass 
rows_per_section = num_rows // 10 

print 'number of rows: {:,d}'.format(num_rows) 
print 'rows per section: {:,d}'.format(rows_per_section) 

csv_files = [open(file_name, 'rb') for _ in xrange(10)] 
csv_readers = [csv.reader(f) for f in csv_files] 
map(next, csv_readers) # skip header 

# position each file handle at its starting position in file 
for i in xrange(10): 
    for j in xrange(i * rows_per_section): 
     try: 
      next(csv_readers[i]) 
     except StopIteration: 
      pass 

# read rows from each of the sections 
for i in xrange(rows_per_section): 
    # elements are one row from each section 
    rows = [next(r) for r in csv_readers] 
    print rows # show what was read 

# clean up 
for i in xrange(10): 
    csv_files[i].close() 

выход:

number of rows: 10,000 
rows per section: 1,000 
[['1'], ['1001'], ['2001'], ['3001'], ['4001'], ['5001'], ['6001'], ['7001'], ['8001'], ['9001']] 
[['2'], ['1002'], ['2002'], ['3002'], ['4002'], ['5002'], ['6002'], ['7002'], ['8002'], ['9002']] 
... 
[['998'], ['1998'], ['2998'], ['3998'], ['4998'], ['5998'], ['6998'], ['7998'], ['8998'], ['9998']] 
[['999'], ['1999'], ['2999'], ['3999'], ['4999'], ['5999'], ['6999'], ['7999'], ['8999'], ['9999']] 
[['1000'], ['2000'], ['3000'], ['4000'], ['5000'], ['6000'], ['7000'], ['8000'], ['9000'], ['10000']] 
Смежные вопросы