4. 输入格式支持:FASTQ格式、压缩文件、paired-end/single-end

做NGS数据分析这几年,我见过不少人在第一步就栽跟头。明明数据质量不错,跑Trimmomatic却报错。原因?对输入格式的理解不到位。说白了,这个工具对输入格式有自己的一套规矩。懂了,就顺了;不懂,就卡住。

4.1 FASTQ格式:必须遵守的规矩

Trimmomatic只认FASTQ格式,不认FASTA。这是底线。FASTQ和FASTA的核心区别在于质量分数。你想想看,没有质量分数,Trimmomatic拿什么判断该切哪里?

一个标准的FASTQ记录长这样:

@SEQ_ID
GATTTGGGGTTCAAAGCAGTATCGATCAAATAGTAAATCCATTTGTTCAACTCACAGTTT
+
!''*((((***+))%%%++)(%%%%).1***-+*''))**55CCF>>>>>>CCCCCCC65

这里有个容易踩的坑:质量分数编码方案。Trimmomatic默认使用Phred+33(即ASCII码33-126),这是Illumina 1.8+的官方标准。但我曾遇到过一批旧数据,用的还是Phred+64编码,直接喂给Trimmomatic,结果质控报告惨不忍睹。

注意:如果你的数据来自Solexa或早期Illumina平台(1.3-1.7),必须显式指定质量编码方式。命令加上参数 -phred64,否则所有碱基的质量都会被严重误判。

我个人习惯拿到新数据后,先用 head -n 40 瞄一眼质量分数这行。如果看到大量@符号或大写字母,大概率是Phred+64。如果看到标点符号和小写字母,通常就是Phred+33。

4.2 压缩文件:Trimmomatic直接读

这点我特别喜欢:Trimmomatic原生支持gzip压缩文件。你不需要手动解压。直接喂 .fastq.gz 文件,它自己知道怎么处理。

为什么要强调这个?我在128核服务器上处理过一个项目,总共48个样本,每个样本的FASTQ文件解压后超过10GB。如果用传统做法,先解压再跑,单是磁盘I/O就能把时间拉长3-5倍。Trimmomatic直接读gz,省了临时空间,也省了解压的时间。

典型用法:

java -jar trimmomatic-0.39.jar PE \
  input_forward.fastq.gz \
  input_reverse.fastq.gz \
  output_forward_paired.fastq.gz \
  output_forward_unpaired.fastq.gz \
  output_reverse_paired.fastq.gz \
  output_reverse_unpaired.fastq.gz \
  ILLUMINACLIP:TruSeq3-PE.fa:2:30:10 \
  LEADING:3 TRAILING:3 SLIDINGWINDOW:4:15 MINLEN:36
小技巧:输出文件也建议直接写 .fastq.gz。Trimmomatic会根据扩展名自动决定是否压缩。这样生成的质控后数据开箱即用,不需要再单独跑一次压缩。

不过有一个细节需要注意:确保你的系统上有gzip命令。Trimmomatic实际上是在底层调用了系统的压缩/解压工具。Windows环境下如果没配好环境变量,可能会报“Cannot run program”的错误。我当年在Windows上折腾了半天才发现是这问题。

4.3 Paired-end vs Single-end:不只是名字不同

这是新手问得最多的问题,也是我刚开始时最迷糊的地方。Paired-end(PE)和Single-end(SE)在Trimmomatic里的处理逻辑完全不同。

原因很简单:PE数据需要保持双端序列的配对关系。你剪切掉一条read的5'端,另一边对应的read也必须做同样的操作。否则后续比对时,两条read就"对不上号"了。

Trimmomatic用 PE 和 SE 两个子命令来区分模式。

模式 子命令 输入文件数 输出文件数 核心逻辑
Single-end SE 1个输入 1个输出 每条read独立处理
Paired-end PE 2个输入(forward + reverse) 4个输出(paired + unpaired 各2个) 双端联动,保持配对

PE模式下,输出为什么是4个文件?你可以这样理解:

  • paired:两条read都通过了质控,可以配对使用。
  • unpaired:其中一条read被丢弃了,剩下那条读成了"单身",没法再用于双端比对,但可能还有分析价值(比如用于覆盖度统计)。

输出结构对比:

# Single-end模式:1个输入 → 1个输出
java -jar trimmomatic-0.39.jar SE input.fastq.gz output.fastq.gz LEADING:3

# Paired-end模式:2个输入 → 4个输出
java -jar trimmomatic-0.39.jar PE \
  R1.fastq.gz R2.fastq.gz \
  R1_paired.fastq.gz R1_unpaired.fastq.gz \
  R2_paired.fastq.gz R2_unpaired.fastq.gz \
  LEADING:3
关键原则:Paired-end数据在质控后,两条read的长度必须始终对齐。如果R1被切短了10bp,R2也必须切短10bp(如果trim操作是对称的)。Trimmomatic会自动处理这个对齐,你不需要手动干预。

为什么会有人在这里出错?我遇到过一位同行,他跑PE数据时只写了2个输出参数,结果报了一个奇怪的参数异常错误。检查后发现,他把PE模式当成了SE模式——只给了一对输出文件。记住:PE模式必须提供4个输出文件名,顺序也不能搞反。

4.4 实战中如何快速确定输入类型

拿到一批数据,如何快速知道它是PE还是SE?我一般看文件名:

  • 文件名包含 _R1_ 和 _R2_ 或 _1 和 _2 → PE数据
  • 文件名只有 _R1_ 或单独的文件名 → SE数据

但这不是100%可靠。有些公开数据集命名不规范。最保险的方法是检查每条FASTQ记录的ID行:如果两条read的ID相同(除了末尾的/1和/2),那就是PE数据。

# PE数据的ID行示例
@EAS139:136:FC706VJ:2:2104:15343:197393 1:Y:18:ATCACG
@EAS139:136:FC706VJ:2:2104:15343:197393 2:Y:18:ATCACG

# SE数据的ID行示例(没有配对标识)
@EAS139:136:FC706VJ:2:2104:15343:197393

嗯,这里要注意:有些平台的PE数据在ID末尾没有/1和/2,而是用空格后的字段区分。关键看两条read的ID是否高度相似(通常只有末尾的字段不同)。

4.5 本章知识结构概览

我把这一节的核心逻辑画成了一张流程图。你看着图,基本就能搞懂Trimmomatic的输入处理逻辑了。

Trimmomatic 输入格式决策流程 识别输入数据 数据格式 FASTQ / 其他? ❌ 报错 不支持FASTA 压缩检查 .fastq / .fastq.gz ? .fastq 直接读取 .fastq.gz 自动解压 配对模式判断 SE模式 1进1出 PE模式 2进4出 ⚠️ 注意:PE模式下,输出必须指定4个文件(2 paired + 2 unpaired),顺序不可颠倒