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 и вуаля! Вы получаете номера строк, содержащих этот эшафот! Возможно, в течение миллисекунд!

Другие вопросы по тегам