разбить текстовую базу данных на N равных блоков и сохранить заголовок

У меня есть несколько больших (30+ миллионов строк) текстовых баз данных, которые я очищаю с помощью следующего кода: мне нужно разбить файл на 1 миллион строк или меньше и сохранить строку заголовка. Я просмотрел chunk и itertools, но не могу найти четкого решения. Он предназначен для использования в модели arcgis.

== обновленный код в соответствии с ответом от icyrock.com

import arcpy, os
#fc = arcpy.GetParameter(0)
#chunk_size = arcpy.GetParameter(1) # number of records in each dataset

fc='input.txt'
Name = fc[:fc.rfind('.')]
fl = Name+'_db.txt'

with open(fc) as f:
  lines = f.readlines()
lines[:] = lines[3:]
lines[0] = lines[0].replace('Rx(db)', 'Rx_'+Name)
lines[0] = lines[0].replace('Best Unit', 'Best_Unit')
records = len(lines)
with open(fl, 'w') as f: #where N is the chunk number
  f.write('\n'.join(lines))

with open(fl) as file:
  lines = file.readlines()

headers = lines[0:1]
rest = lines[1:]
chunk_size = 1000000

def chunks(lst, chunk_size):
  for i in xrange(0, len(lst), chunk_size):
    yield lst[i:i + chunk_size]

def write_rows(rows, file):
  for row in rows:
    file.write('%s' % row)

part = 1
for chunk in chunks(rest, chunk_size):
  with open(Name+'_%d' % part+'.txt', 'w') as file:
    write_rows(headers, file)
    write_rows(chunk, file)
  part += 1

См. Удаление определенных строк из большого текстового файла в python и разбить большую текстовую (xyz) базу данных на x равных частей для фона. Мне больше не нужно решение на основе cygwin, поскольку оно слишком усложняет модель. Мне нужен питонический способ. Мы можем использовать «записи» для итерации, но неясно, как указать строку 1: 999 999 в db # 1, строки с 1 000 0000 по 1 999 999 в db # 2 и т. д. Это нормально, если последний набор данных имеет менее 1 м записи.

Ошибка с файлом 500mb (у меня 16GB RAM).

Трассировка (последний последний вызов): файл «P:\2012\Job_044_DM_Radio_Propogation\Working\test\clean_file.py», строка 10, in lines = f.readlines() MemoryError

записи 2249878

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

=== С новым кодом от Icyrock.

Чанк работает нормально, но выдает ошибки при использовании в Arcgis.

Время начала: Пт, 09 марта, 17:20:04 2012 ПРЕДУПРЕЖДЕНИЕ 000594: Входной объект 1945882430: выходит за пределы доменов выходной геометрии. ПРЕДУПРЕЖДЕНИЕ 000595: d:\Temp\cb_vhn007_1.txt_Features1.fid содержит полный список функций, которые невозможно скопировать.

Я знаю, что это проблема с фрагментацией, так как процесс «Создать слой событий» отлично работает с полным набором данных до фрагментации.

Любые идеи?


person GeorgeC    schedule 08.03.2012    source источник


Ответы (1)


Вы можете сделать что-то вроде этого:

with open('file') as file:
  lines = file.readlines()

headers = lines[0:1]
rest = lines[1:]
chunk_size = 4

def chunks(lst, chunk_size):
  for i in xrange(0, len(lst), chunk_size):
    yield lst[i:i + chunk_size]

def write_rows(rows, file):
  for row in rows:
    file.write('%s' % row)

part = 1
for chunk in chunks(rest, chunk_size):
  with open('part%d' % part, 'w') as file:
    write_rows(headers, file)
    write_rows(chunk, file)
  part += 1

Вот тестовый запуск:

$ cat file && python mkt.py && for p in part*; do echo ---- $p; cat $p; done
header
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---- part1
header
1
2
3
4
---- part2
header
5
6
7
8
---- part3
header
9
10
11
12
---- part4
header
13
14

Очевидно, измените значения chunk_size и способ получения headers в зависимости от их количества.

Кредиты:

Изменить - чтобы сделать это построчно, чтобы избежать проблем с памятью, вы можете сделать что-то вроде этого:

from itertools import islice

headers_count = 5
chunk_size = 250000

with open('file') as fin:
  headers = list(islice(fin, headers_count))

  part = 1
  while True:
    line_iter = islice(fin, chunk_size)
    try:
      first_line = line_iter.next()
    except StopIteration:
      break
    with open('part%d' % part, 'w') as fout:
      for line in headers:
        fout.write(line)
      fout.write(first_line)
      for line in line_iter:
        fout.write(line)
    part += 1

Кредиты:

Тестовый пример (поместите вышеуказанное в файл с именем mkt2.py):

Создайте файл, содержащий 5-строчный заголовок и 1234567 строк в нем:

with open('file', 'w') as fout:
  for i in range(5):
    fout.write(10 * ('header %d ' % i) + '\n')
  for i in range(1234567):
    fout.write(10 * ('line %d ' % i) + '\n')

Сценарий оболочки для тестирования (поместите в файл с именем rt.sh):

rm part*
echo ---- file
head -n7 file
tail -n2 file

python mkt2.py

for i in part*; do
  echo ---- $i
  head -n7 $i
  tail -n2 $i
done

Пример вывода:

$ sh rt.sh 
---- file
header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 
header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 
header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 
header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 
header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 
line 0 line 0 line 0 line 0 line 0 line 0 line 0 line 0 line 0 line 0 
line 1 line 1 line 1 line 1 line 1 line 1 line 1 line 1 line 1 line 1 
line 1234565 line 1234565 line 1234565 line 1234565 line 1234565 line 1234565 line 1234565 line 1234565 line 1234565 line 1234565 
line 1234566 line 1234566 line 1234566 line 1234566 line 1234566 line 1234566 line 1234566 line 1234566 line 1234566 line 1234566 
---- part1
header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 
header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 
header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 
header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 
header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 
line 0 line 0 line 0 line 0 line 0 line 0 line 0 line 0 line 0 line 0 
line 1 line 1 line 1 line 1 line 1 line 1 line 1 line 1 line 1 line 1 
line 249998 line 249998 line 249998 line 249998 line 249998 line 249998 line 249998 line 249998 line 249998 line 249998 
line 249999 line 249999 line 249999 line 249999 line 249999 line 249999 line 249999 line 249999 line 249999 line 249999 
---- part2
header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 
header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 
header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 
header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 
header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 
line 250000 line 250000 line 250000 line 250000 line 250000 line 250000 line 250000 line 250000 line 250000 line 250000 
line 250001 line 250001 line 250001 line 250001 line 250001 line 250001 line 250001 line 250001 line 250001 line 250001 
line 499998 line 499998 line 499998 line 499998 line 499998 line 499998 line 499998 line 499998 line 499998 line 499998 
line 499999 line 499999 line 499999 line 499999 line 499999 line 499999 line 499999 line 499999 line 499999 line 499999 
---- part3
header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 
header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 
header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 
header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 
header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 
line 500000 line 500000 line 500000 line 500000 line 500000 line 500000 line 500000 line 500000 line 500000 line 500000 
line 500001 line 500001 line 500001 line 500001 line 500001 line 500001 line 500001 line 500001 line 500001 line 500001 
line 749998 line 749998 line 749998 line 749998 line 749998 line 749998 line 749998 line 749998 line 749998 line 749998 
line 749999 line 749999 line 749999 line 749999 line 749999 line 749999 line 749999 line 749999 line 749999 line 749999 
---- part4
header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 
header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 
header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 
header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 
header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 
line 750000 line 750000 line 750000 line 750000 line 750000 line 750000 line 750000 line 750000 line 750000 line 750000 
line 750001 line 750001 line 750001 line 750001 line 750001 line 750001 line 750001 line 750001 line 750001 line 750001 
line 999998 line 999998 line 999998 line 999998 line 999998 line 999998 line 999998 line 999998 line 999998 line 999998 
line 999999 line 999999 line 999999 line 999999 line 999999 line 999999 line 999999 line 999999 line 999999 line 999999 
---- part5
header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 header 0 
header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 header 1 
header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 header 2 
header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 header 3 
header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 header 4 
line 1000000 line 1000000 line 1000000 line 1000000 line 1000000 line 1000000 line 1000000 line 1000000 line 1000000 line 1000000 
line 1000001 line 1000001 line 1000001 line 1000001 line 1000001 line 1000001 line 1000001 line 1000001 line 1000001 line 1000001 
line 1234565 line 1234565 line 1234565 line 1234565 line 1234565 line 1234565 line 1234565 line 1234565 line 1234565 line 1234565 
line 1234566 line 1234566 line 1234566 line 1234566 line 1234566 line 1234566 line 1234566 line 1234566 line 1234566 line 1234566 

Сроки вышеперечисленного:

real    0m0.935s
user    0m0.708s
sys     0m0.200s

Надеюсь это поможет.

person icyrock.com    schedule 08.03.2012
comment
Спасибо, но из-за размера я получаю ошибку памяти. Смотрите обновленный вопрос. Можем ли мы изменить rest = line на - lines[1:1000000] при запуске 1, затем lines[10000001:2000000] и т. д.? - person GeorgeC; 09.03.2012
comment
См. редактирование версии, которая работает построчно, что позволяет избежать проблем с памятью в больших файлах. Для разбиения файла из 1+ миллиона строк на 250 тыс. частей строк требуется менее секунды, поэтому в вашем случае это должно работать достаточно хорошо. - person icyrock.com; 09.03.2012
comment
Спасибо, кажется, это работает нормально, но затем, когда я пытаюсь обработать его в arcgis, я получаю сообщение об ошибке. Я знаю, что это как-то связано с фрагментированием, так как процесс копирования работает нормально для полного файла перед фрагментом. Мне нужен был кусок, так как другие процессы не работали из-за размера. Смотрите обновление к вопросу. - person GeorgeC; 09.03.2012
comment
Извините, не знаком с arcgis. Возможно ли, что линии связаны? Например. если вы попытаетесь скопировать заголовок и 10 случайных строк из вашего файла, это вообще сработает? Если нет, то фрагментация не удастся. - person icyrock.com; 10.03.2012