Самый быстрый способ прочитать fastq с scikit-био

Я пытаюсь прочитать отформатированный текст fastq с помощью http://scikit-bio.org/.

Учитывая, что это довольно большой файл, выполнение операций выполняется довольно медленно.

В конечном итоге я пытаюсь удалить файл fastq в словарь:

f = 'Undetermined_S0_L001_I1_001.fastq'
seqs = skbio.io.read(f, format='fastq')

seq_dic = {}
for seq in seqs:
    seq = str(seq)
    if seq in seq_dic.keys():
        seq_dic[seq] +=1
    else:
        seq_dic[seq] = 1

Большая часть времени здесь используется во время чтения файла:

%%time
f = 'Undetermined_S0_L001_I1_001.fastq'
seqs = skbio.io.read(f, format='fastq')

for seq in itertools.islice(seqs, 100000):
    seq

CPU times: user 46.2 s, sys: 334 ms, total: 46.5 s
Wall time: 47.8 s

Насколько я понимаю, не проверка последовательностей может улучшить время выполнения, однако это не так:

%%time
f = 'Undetermined_S0_L001_I1_001.fastq'
seqs = skbio.io.read(f, format='fastq', verify=False, variant='illumina1.8')

for seq in itertools.islice(seqs, 100000):
    seq

CPU times: user 47 s, sys: 369 ms, total: 47.4 s
Wall time: 48.9 s

Итак, мой вопрос, во-первых, почему нет verify=False Как улучшить время выполнения и секунды? Есть ли более быстрый способ использования scikit-bio для чтения последовательностей?

2 ответа

Решение

первое почему не проверить = ложное улучшение времени выполнения

verify=False является параметром, принятым API ввода / вывода scikit-bio в целом. Это не относится к конкретному формату файла. verify=False говорит scikit-bio не вызывать анализатор формата файла, чтобы дважды проверить, что файл находится в формате, указанном пользователем. Из документов [1]:

verify : bool, optional
    When True, will double check the format if provided.

Так verify=False не отключает проверку данных последовательности; отключает проверку формата сниффера. Вы будете иметь минимальный прирост производительности с verify=False,

seqs = skbio.io.read(f, format='fastq', verify=False, variant='illumina1.8') будет производить генератор skbio.Sequence объекты. Проверка последовательности алфавита не выполняется, потому что skbio.Sequence не имеет алфавита, так что это не то, где ваше узкое место производительности. Обратите внимание, что если вы хотите прочитать файл FASTQ в определенный тип биологической последовательности (ДНК, РНК или белок), вы можете передать constructor=skbio.DNA (например). Это выполнит проверку алфавита для соответствующего типа последовательности, который в настоящее время не может быть отключен при чтении. Поскольку у вас проблемы с производительностью, я не рекомендую проходить constructor поскольку это только замедлит вещи еще больше.

а во-вторых, есть ли более быстрый способ использования scikit-bio для чтения последовательностей?

Нет более быстрого способа чтения файлов FASTQ с помощью scikit-bio. Существует проблема [2], исследующая идеи, которые могут ускорить это, но эти идеи не были реализованы.

scikit-bio медленно читает файлы FASTQ, поскольку поддерживает чтение данных последовательности и показателей качества, которые могут занимать несколько строк. Это усложняет логику чтения и снижает производительность. Однако файлы FASTQ с многострочными данными больше не распространены; Illumina раньше создавала эти файлы, но теперь они предпочитают / рекомендуют писать записи FASTQ, которые состоят ровно из четырех строк (заголовок последовательности, данные последовательности, заголовок качества, показатели качества). Фактически, именно так scikit-bio записывает данные FASTQ. С этим более простым форматом записи намного быстрее и проще читать файл FASTQ. scikit-bio также медленно читает файлы FASTQ, поскольку декодирует и проверяет показатели качества. Он также хранит данные последовательности и показатели качества в skbio.Sequence объект, который имеет служебную нагрузку.

В вашем случае вам не нужно декодировать показатели качества, и, скорее всего, у вас есть файл FASTQ с простыми четырехстрочными записями. Вот Python 3-совместимый генератор, который читает файл FASTQ и выдает данные последовательности в виде строк Python:

import itertools

def read_fastq_seqs(filepath):
    with open(filepath, 'r') as fh:
        for seq_header, seq, qual_header, qual in itertools.zip_longest(*[fh] * 4):
            if any(line is None for line in (seq_header, seq, qual_header, qual)):
                raise Exception(
                    "Number of lines in FASTQ file must be multiple of four "
                    "(i.e., each record must be exactly four lines long).")
            if not seq_header.startswith('@'):
                raise Exception("Invalid FASTQ sequence header: %r" % seq_header)
            if qual_header != '+\n':
                raise Exception("Invalid FASTQ quality header: %r" % qual_header)
            if qual == '\n':
                raise Exception("FASTQ record is missing quality scores.")

            yield seq.rstrip('\n')

Вы можете удалить проверочные проверки здесь, если вы уверены, что ваш файл является допустимым файлом FASTQ, содержащим записи, длина которых ровно четыре строки.

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

if seq in seq_dic:  # calling .keys() is necessary
    seq_dic[seq] +=1
else:
    seq_dic[seq] = 1

[1] http://scikit-bio.org/docs/latest/generated/skbio.io.registry.read.html

[2] https://github.com/biocore/scikit-bio/issues/907

Если вы хотите посчитать количество вхождений каждой уникальной последовательности в файле fastq, я бы предложил попробовать анализатор банка pyGATB вместе с удобным Counter объект из collections модуль стандартной библиотеки.

#!/usr/bin/env python3

from collections import Counter
from gatb import Bank

# (gunzipping is done transparently)
seq_counter = Counter(seq.sequence for seq in Bank("SRR077487_2.filt.fastq.gz"))

Это довольно эффективно для модуля Python (согласно моим тестам в Bioinformatics SE: https://bioinformatics.stackexchange.com/a/380/292).

Этот счетчик должен вести себя как ваш seq_dic плюс несколько удобных методов.

Например, если я хочу напечатать 10 самых частых последовательностей вместе с их количеством:

print(*seq_counter.most_common(10), sep="\n")
Другие вопросы по тегам