Формат FASTQ: последовательности с качеством

FASTQ — это FASTA с приложенным «качеством»: для каждой буквы прибор сообщает, насколько он в ней уверен.

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

Если FASTA — это «чистый текст» собранного генома, то FASTQ — это «сырьё» прямо с прибора. С него начинается почти любой реальный анализ, и контроль качества по FASTQ — первый шаг любого пайплайна.

Четыре строки записи

СтрокаСодержимое
1заголовок, начинается с @
2сама последовательность (буквы A/T/G/C/N)
3разделитель, начинается с + (часто только +)
4строка качества — по одному символу на каждую букву строки 2
@read1
GATTTGGGG
+
!''*((((*

Длина строки качества всегда равна длине последовательности: один символ качества — на одну букву.

Как закодировано качество

Каждый символ качества — это ASCII-код, из которого вычитают 33, чтобы получить Phred-оценку Q. А Q связано с вероятностью ошибки: p = 10^(-Q/10). Чем выше символ в ASCII, тем надёжнее буква.

def phred_scores(qual_string):
    return [ord(ch) - 33 for ch in qual_string]

qual = "!''*((((*"
scores = phred_scores(qual)
print("Символы качества:", list(qual))
print("Phred-оценки:    ", scores)

Вывод:

Символы качества: ['!', "'", "'", '*', '(', '(', '(', '(', '*']
Phred-оценки:     [0, 6, 6, 9, 7, 7, 7, 7, 9]

Символ '!' (ASCII 33) — это Q0, самое плохое качество. Чем «выше» символ по таблице ASCII, тем лучше.

Парсер и фильтр FASTQ

Парсер читает записи блоками по 4 строки. Типичная задача — отбросить риды со средним качеством ниже порога.

fastq = """@read1
GATTTGGGG
+
!''*((((*
@read2
AAACCCGGG
+
IIIIIIIII"""

def parse_fastq(text):
    lines = text.splitlines()
    for i in range(0, len(lines), 4):
        name = lines[i][1:]
        seq = lines[i + 1]
        qual = lines[i + 3]
        yield name, seq, qual

def mean_q(qual):
    scores = [ord(c) - 33 for c in qual]
    return sum(scores) / len(scores)

THRESHOLD = 20
for name, seq, qual in parse_fastq(fastq):
    q = mean_q(qual)
    verdict = "оставить" if q >= THRESHOLD else "выбросить"
    print(f"{name}: средний Q = {q:.1f} -> {verdict}")

Вывод:

read1: средний Q = 6.4 -> выбросить
read2: средний Q = 40.0 -> оставить

read1 шумный (средний Q около 6) и не проходит порог, а read2 идеальный (символ 'I' = Q40) и остаётся. Так выглядит самый базовый шаг контроля качества: отбросить ненадёжные риды ещё до анализа. Порог подбирают под данные и задачу.

Как работает под капотом: кодировки качества

Сдвиг 33 (Phred+33) — современный стандарт (Sanger/Illumina 1.8+). Раньше встречался Phred+64 (старые Illumina). Перепутать кодировку — значит получить бессмысленные оценки качества. Если оценки выходят отрицательными или дико большими — почти наверняка вы взяли не тот сдвиг.

Почему вообще качество кодируют буквами, а не числами? Из соображений компактности и формата. Если бы качество записывали числами через запятую, строка была бы в несколько раз длиннее последовательности и её нельзя было бы выровнять символ-в-символ. Один ASCII-символ на одно основание даёт идеальное соответствие: i-я буква последовательности и i-й символ качества всегда напротив друг друга. Диапазон печатных ASCII-символов от 33 ('!') до 126 ('~') покрывает оценки Q0–Q93 — с огромным запасом, ведь реальные приборы редко дают выше Q40.

В реальных пайплайнах сырой FASTQ почти никогда не идёт в анализ напрямую. Сначала его прогоняют через контроль качества: специальные программы строят отчёты (распределение Q по позициям рида, GC-состав, наличие адаптеров — кусочков искусственной ДНК, оставшихся от подготовки образца), а затем риды чистят — обрезают концы с низким качеством и удаляют адаптеры. Наш простой фильтр «средний Q ниже порога — выбросить» — это самая базовая версия такого шага. Понимание FASTQ и Phred-качества — фундамент, на котором стоят все эти инструменты, даже если в работе вы пользуетесь готовыми программами, а не пишете парсер каждый раз.

Частые ошибки

  • Сдвиг строки на 1. Запись — ровно 4 строки; сбой нумерации рушит весь парсер.
  • Неверный сдвиг кодировки. Phred+33 против Phred+64 — частая причина абсурдных оценок.
  • Игнорировать качество. FASTQ без фильтрации по Q наполняет анализ ошибками прибора.

Итог

  • FASTQ хранит риды с качеством: 4 строки на запись (@id, последовательность, +, качество).
  • Качество — ASCII-символ минус 33 = Phred Q; p_ошибки = 10^(-Q/10).
  • Длина строки качества равна длине последовательности.
  • Первый шаг анализа — фильтрация ридов по качеству (контроль качества).
Проверьте себя
1. Сколько строк занимает одна запись в формате FASTQ?
A1
B2
C4
D8
2. Как из символа качества получить Phred-оценку Q (кодировка Phred+33)?
Aord(символ) + 33
Bord(символ) - 33
Cord(символ) * 33
D33 - ord(символ)
3. Что должно совпадать в записи FASTQ?
AЗаголовок и разделитель
BДлина строки последовательности и длины строки качества
CВсе четыре строки одинаковой длины
DНичего не обязано совпадать