Python большие файлы, как найти конкретные строки с определенной строкой
Я использую Python для обработки данных из очень больших текстовых файлов (~52 ГБ, 800 миллионов строк каждая с 30 столбцами данных). Я пытаюсь найти эффективный способ найти конкретные строки. К счастью, строка всегда находится в первом столбце.
Все это работает, память не проблема (я не загружаю ее, просто открываю и закрываю файл по мере необходимости), и все равно запускаю ее на кластере. Больше о скорости. Сценарий занимает несколько дней!
Данные выглядят примерно так:
scaffold126 1 C 0:0:20:0:0:0 0:0:1:0:0:0 0:0:0:0:0:0
scaffold126 2 C 0:0:10:0:0:0 0:0:1:0:0:0 0:0:0:0:0:0
scaffold5112 2 C 0:0:10:0:0:0 0:0:1:0:0:0 0:0:0:0:0:0
scaffold5112 2 C 0:0:10:0:0:0 0:0:1:0:0:0 0:0:0:0:0:0
и я ищу все строки, которые начинаются с определенной строки из первого столбца. Я хочу обработать данные и отправить резюме в выходной файл. Затем я ищу все строки для другой строки и так далее...
Я использую что-то вроде этого:
for (thisScaff in AllScaffs):
InFile = open(sys.argv[2], 'r')
for line in InFile:
LineList = line.split()
currentScaff = LineList[0]
if (thisScaff == currentScaff):
#Then do this stuff...
Основная проблема заключается в том, что необходимо просмотреть все 800 миллионов строк, чтобы найти те, которые соответствуют текущей строке. Затем, когда я перехожу к другой строке, все 800 должны быть просмотрены снова. Я изучал варианты grep, но есть ли другой способ?
Спасибо заранее!
3 ответа
Моим первым инстинктом было бы загрузить ваши данные в базу данных, убедившись, что создал индекс из столбца 0, а затем запросил по мере необходимости.
Для подхода Python попробуйте это:
wanted_scaffs = set(['scaffold126', 'scaffold5112'])
files = {name: open(name+'.txt', 'w') for name in wanted_scaffs}
for line in big_file:
curr_scaff = line.split(' ', 1)[0] # minimal splitting
if curr_scaff in wanted_scaffs:
files[key].write(line)
for f in files.values():
f.close()
Затем сделайте ваши сводные отчеты:
for scaff in wanted_scaffs:
with open(scaff + '.txt', 'r') as f:
... # summarize your data
Очевидно, вы хотите прочитать файл только один раз. Читать это снова и снова очень дорого. Чтобы ускорить поиск, создайте набор искомых строк. Вот так:
looking_for = set(AllScaffs)
with open(sys.argv[2]) as f:
for line in f:
if line.split(None, 1)[0] in looking_for:
# bingo! found one
line.split(None, 1)
разбивает на пробел, но не более 1 делится. Например,
>>> "abc def ghi".split(None, 1)
['abc', 'def ghi']
Это значительно быстрее, чем разделение 29 раз (что произойдет, если в каждой строке будет 30 столбцов, разделенных пробелами).
Альтернатива:
if line[:line.find(' ')] in looking_for:
Это, вероятно, еще быстрее, так как список не создается вообще. Он ищет крайний левый пробел и берет начальный фрагмент line
до (но не включая) этого бланка.
Создать индекс. Это потребует много места на диске. Используйте его только в том случае, если вам приходится слишком часто выполнять поиск по лесам.
Это будет разовая работа, она займет много времени, но определенно послужит вам в долгосрочной перспективе.
Ваш индекс будет иметь форму:
scaffold126:3|34|234443|4564564|3453454
scaffold666:1|2
scaffold5112:4|23|5456456|345345|234234
где 3,4 и т. д. - номера строк. Убедитесь, что окончательный файл отсортирован по алфавиту (чтобы освободить место для бинарного поиска). Давайте назовем этот индекс как Index_Primary
Теперь вы создадите вторичный индекс, чтобы сделать поиск быстрее. Давайте назовем это Index_Second. Допустим, Index_Primary содержит сто тысяч строк, каждая строка представляет один каркас. Index_Second даст нам точки прыжка. Это может быть как:
scaffold1:1
scaffold1000:850
scaffold2000:1450
Это говорит о том, что информация о scaffold2000 присутствует в строке 1450 Index_Primary.
Итак, теперь предположим, что вы хотите найти строки с помощью scaffold1234, вы перейдете к Index_Second. Это скажет вам, что scaffold1234 присутствует где-то между строкой 850 и 1450 Index_Primary. Теперь загрузите его и начните с середины этого блока, т. Е. Строки 1150. Найдите необходимый эшафот, используя Binary Search и вуаля! Вы получаете номера строк, содержащих этот эшафот! Возможно, в течение миллисекунд!