Сохранить строку текста, если ее обработала другая конкретная строка текста? - PullRequest
1 голос
/ 11 марта 2019

Извините за плохое название, я не знаю, как еще сформулировать мой вопрос.

Я написал скрипт, который извлекает данные из файлов fastq (текстовые файлы геномного чтения).Каждая 1-я строка является заголовком, 2-я строка является базовой строкой - 3-я и 4-я строки не нужны.

filename = 'C0_GGCTAC_R1_no_adapter_trimming.fastq'
new_filename = filename[:-9] + '_new.fastq'

with open(filename) as f_obj:
    file_contents = f_obj.readlines()

extracted_lines = ''
line_count = 0

# Pull header and base lines
for line in file_contents:
    line_count += 1
    # Headers
    if line_count == 1:
        extracted_lines += line
    # Reads ending in A
    elif line_count == 2 and line[-2] == 'A':
        extracted_lines += line
    # Reads ending in G
    elif line_count == 2 and line[-2] == 'G':
        extracted_lines += line
    # Reset counter
    elif line_count == 4:
        line_count = 0

with open(new_filename, 'w') as f_obj:
    f_obj.write(extracted_lines)
print(new_filename + " was created.")

Скрипт извлекает заголовок каждого чтения и строку баз в прочитанном, если чтение баз заканчивается на A или G. Пример входного файла будет:

@HWI-D00461:137:C9H2FACXX:3:1101:1239:1968 1:N:0:GGCTAC
NTGTGTAATAGATTTTACTTTTGCCTTTAAGCCCAAGGTCCTGGACTTGAAACATCCAAGGGATGGAAAATGCCGTATAACAGGGTGGAAGAGAGATTTGA
+
#1=BDDFFHHHFHIJJJJJJJJJJJJJJJJJJJJJIJJIJJJJJHJIIJHGIJJJJJJIHJJBGHJHIIJJJHHHHFFFFEEEDD;?BACDDDA?@CDDDC
@HWI-D00461:137:C9H2FACXX:3:1101:1117:1968 1:N:0:GGCTAC
NAAAGTCTACCAATTATACTTAGTGTGAAGAGGTGGGAGTTAAATATGACTTCCATTAATAGTTTCATTGTTTGGAAAACAGAGGTAATTTTTGATACAGA
+
#1=DDDFDFHHHGHIIGJJJJHIJIHHDIHHIJGGEI@GFGHIHIJHEFHIIIIGIJGHHGECFGIDHGIHIIEGIIJHHEEFFF7?ACEECCBBDEDDDC

Выходной файл выглядит следующим образом.

@HWI-D00461:137:C9H2FACXX:3:1101:1117:1968 1:N:0:GGCTAC
NAAAGTCTACCAATTATACTTAGTGTGAAGAGGTGGGAGTTAAATATGACTTCCATTAATAGTTTCATTGTTTGGAAAACAGAGGTAATTTTTGATACAGA
@HWI-D00461:137:C9H2FACXX:3:1101:1200:1972 1:N:0:GGCTAC
@HWI-D00461:137:C9H2FACXX:3:1101:1087:1973 1:N:0:GGCTAC
NTAATCCAACTAACTAAAAATAAAAAGATTCAAATAGGTACAGAAAACAATGAAGGTGTAGAGGTGAGAAATCAACAGGATGTTCAGAAGCCTGTGTATGA

Хотя он содержит все данные, которые необходимы, он вытягивает каждую строку заголовка (начинается с '@'), что не нужно.

Как я могу изменить свой код, чтобы вытащить только строку заголовка, если за ней следует строка оснований, оканчивающаяся на A или G?

Ответы [ 2 ]

1 голос
/ 11 марта 2019

Проблема в том, что вы добавляете id к каждой записи, а не только к тем, которые вас интересуют. Быстрое решение - сохранить id в переменная и добавляйте ее только тогда, когда это необходимо:

filename = 'C0_GGCTAC_R1_no_adapter_trimming.fastq'
new_filename = filename[:-9] + '_new.fastq'

with open(filename) as f_obj:
    file_contents = f_obj.readlines()

extracted_lines = ''
line_count = 0

# Pull header and base lines
for line in file_contents:
    line_count += 1
    # Headers
    if line_count == 1:
        id_string = line
    # Reads ending in A
    elif line_count == 2 and line[-2] == 'A':
        extracted_lines += id_string
        extracted_lines += line
    # Reads ending in G
    elif line_count == 2 and line[-2] == 'G':
        extracted_lines += id_string
        extracted_lines += line
    # Reset counter
    elif line_count == 4:
        line_count = 0

with open(new_filename, 'w') as f_obj:
    f_obj.write(extracted_lines)
print(new_filename + " was created.")

Я также должен сказать, что этот код не очень эффективен, особенно с точки зрения использования памяти: вы читаете (обычно) очень большой файл в память, но вам нужна только одна запись за раз.

Вторичные проблемы заключаются в том, что ваши условия могут быть сжаты, и вы можете работать с модулями, чтобы знать, в каком типе линии вы находитесь:

filename = 'C0_GGCTAC_R1_no_adapter_trimming.fastq'
new_filename = filename[:-9] + '_new.fastq'

with open(filename) as in_f_obj, open(new_filename, 'w') as out_f_obj:
    # Process the file
    line_count = 0
    for line in in_f_obj:
        line_count += 1

        # Extract the information for each record
        if line_count % 4 == 1:
            id_string = line
        elif line_count % 4 == 2:
            seq = line
        elif line_count % 4 == 3:
            extra = line
        elif line_count % 4 == 4:
            # Last part of the record. Here we have all the information
            # and we can decide if we want to output something
            # and what we want to output
            qual = line
            if seq[-2] == 'A' or seq[-2] == 'G'
                out_f_obj.write(id_string)
                out_f_obj.write(seq)

print(new_filename + " was created.")

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

Я бы добавил дополнительную деталь, я бы вырезал новую строку в каждой строке чтения и добавлял ее при необходимости при написании:

# Extract the information for each record
if line_count % 4 == 1:
    id_string = line.rstrip()
elif line_count % 4 == 2:
    seq = line.rstrip()
elif line_count % 4 == 3:
    extra = line.rstrip()
elif line_count % 4 == 4:
    # Last part of the record. Here we have all the information
    # and we can decide if we want to output something
    # and what we want to output
    qual = line.rstrip()
    if seq[-1] == 'A' or seq[-1] == 'G'
        out_f_obj.write("{}\n{}\n".format(id_string, seq))

Таким образом, ваши данные чистые, без форматирования новой строки из входного файла.

0 голосов
/ 11 марта 2019

Я думаю, это облегчит вашу задачу, пройдя по файлу в 4 строки, а не в одну строку.По крайней мере, предполагая, что на самом деле всегда есть постоянно 4 линии, которые принадлежат друг другу.Затем вы можете отфильтровать нужные базы перед добавлением соответствующей строки заголовка, например, так:

extracted_lines = []
for i in range(0, len(file_contents), 4):
    header, bases, comment1, comment2 = file_contents[i:i+4]
    if bases[-1] in ["A", "G"]:
        extracted_lines.append(header)
        extracted_lines.append(bases)
...