3. Illumina 测序平台命名规则详解:仪器ID、流道、位置、双端索引
好,咱们进入第三章。我相信你手头肯定遇到过一堆长文件名,看起来像一串乱码。别慌,Illumina的命名规则其实非常固定,它就是一把钥匙。只要掌握了这把钥匙,提取批次信息就像查字典一样简单。
我个人习惯,拿到一个FASTQ文件,第一件事不是打开看内容,而是先盯着文件名看十秒钟。为什么?因为文件名已经把样本的“出生证明”写得明明白白了——在哪台机器上测的、在芯片哪个位置、用了哪个文库。
3.1 完整文件名结构解析
Illumina的FASTQ文件命名格式,说白了就是一串用下划线拼接的字段。我拿一个真实项目的例子跟你讲:
Sample1_S1_L001_R1_001.fastq.gz
这个文件名拆开来看,各个部分的含义如下表:
| 字段 | 示例值 | 含义 |
|---|---|---|
| 样本名 | Sample1 | 由用户或样本表自定义,用于区分不同样本 |
| 样本编号 | S1 | Illumina软件自动分配的编号,同一run内唯一 |
| Lane编号 | L001 | 表明该数据来自哪个lun(流道),三位数补零,比如L001 |
| Read方向 | R1 | 双端测序时R1代表第一端,R2代表第二端 |
| Set Partition | 001 | 拆分的块编号,如果单个文件过大就会拆成多个 |
3.2 仪器ID与Run编号
上面的最简格式其实还少了一个重要字段——完整格式里仪器ID和Run编号会作为前缀。你再看看这个:
MISEQ01_20231017_Sample1_S1_L001_R1_001.fastq.gz
嗯,这里要注意,“MISEQ01”就是仪器ID,“20231017”通常是测序开始的日期(作为Run编号)。为什么我要提这个?因为批次信息提取的核心就靠这两个字段。不同仪器之间试剂的剂量、出错概率都可能有差异,如果不区分仪器就把所有FASTQ混在一起分析,你可能会踩坑。
我把常见仪器的命名前缀列出来,你参考一下:
| 平台 | 典型仪器ID样式 |
|---|---|
| MiSeq | MISEQ01、M02134 |
| NextSeq 500/550 | NB501234、VH00123 |
| HiSeq 2500/4000 | HISEQ01、D00535 |
| NovaSeq 6000 | A00123、NS500256 |
你看,每个仪器都有自己的“身份证号”。我建议你在做批次汇总时,把仪器ID作为分组的第一层key,这样能迅速看出哪个批次的数据是同一台机器产出的。
3.3 流道(Lane)与位置信息
Illumina的测序芯片通常有多个流道,数据产出后每个流道会生成独立的FASTQ文件。比如L001、L002、L003、L004分别代表四个流道。
为什么会这样设计?你想想看,同一张芯片上不同流道的数据,如果某个流道出现气泡或者堵塞,只影响那个流道的质量。如果我在处理数据时发现某个Lane的读段比例明显偏低,我就会怀疑那个流道有问题,直接跳过不用,其他流道的数据照样能用。
有的平台还会包含Tile位置信息,不过那个通常只在中间文件或者BCL转换日志里出现。比如:
Sample1_S1_L001_R1_001.fastq.gz # 标准文件
1101_20231017_1_1101_20231017.bcl # BCL转换日志里会有tile编号
3.4 双端索引(Index)与样本区分
现在的Illumina测序都走双端索引(dual index)。什么意思?就是一条读段有两个Index,一个叫i7,一个叫i5。它们被写在FASTQ文件的header里,而不是文件名里。不过,文件名通常会在样本名里体现索引信息。
你看这个示例:
SampleA_GTAGAGGA-CTCTCTAT_L001_R1_001.fastq.gz
“GTAGAGGA”是i7索引序列,“CTCTCTAT”是i5索引序列。这个组合就是这条数据的“指纹”。
为什么强调这一点?因为双端索引大大提高了多路复用(multiplexing)的准确性。以前单端索引容易串样,现在双端索引很少出现index hopping的问题。不过,我做生信分析时还是会验证一下——把FASTQ header里的索引序列和样本表做比对,确认样本没有被交换。
提取索引序列的方法其实很简单,用zcat加head就能看到:
zcat SampleA_GTAGAGGA-CTCTCTAT_L001_R1_001.fastq.gz | head -1
输出大概长这样:
@A00123:1:1101:1000:10000#GTAGAGGA+CTCTCTAT 1:N:0:GTAGAGGA+CTCTCTAT
我一般用+号前后两部分来识别索引,加号前是i7,加号后是i5。一个经验之谈:如果跑完测序发现某个样本的读段数特别少,先去看看FASTQ header里的索引序列跟你当初录入的是不是一致,经常有人写错样本表。
3.5 实战:手写一个命名解析函数
说了这么多,不如直接上代码。我一般用Python写一个解析函数,目标就是从文件名里提取出仪器ID、Run编号、Lane、索引序列这四个关键字段。下面是我在几个项目中反复使用的一个版本:
import re
def parse_fastq_filename(filename):
"""
解析Illumina FASTQ文件名,返回批次信息字典。
支持两种格式:
1. Sample_Index_L001_R1_001.fastq.gz
2. Instrument_RunDate_Sample_Index_L001_R1_001.fastq.gz
"""
# 去掉.gz后缀
base = filename.replace('.fastq.gz', '')
# 定义输出结构
info = {
'instrument': '',
'run_date': '',
'sample_name': '',
'index_i7': '',
'index_i5': '',
'lane': '',
'read_direction': ''
}
# 按下划线分割
parts = base.split('_')
# 判断是否包含仪器信息:第一段是字母数字混合且不是标准样本名
# 如果第一段包含字母和数字(长度<10),认为是仪器ID
if re.match(r'^[A-Za-z0-9]{4,8}$', parts[0]):
info['instrument'] = parts[0]
info['run_date'] = parts[1]
parts = parts[2:]
# 提取样本名和索引:惯例是样本名_索引i7-索引i5
sample_field = parts[0]
# 如果有连字符,说明样本名和索引是分开的
if '-' in sample_field:
# 有的样本名本身带下划线,比如Sample_01_GTAGAGGA-CTCTCTAT
# 这里简化处理:认为最后一个带连字符的字段是索引
# 更健壯的做法是用正则匹配索引模式
idx_match = re.search(r'([ATCG]+)-([ATCG]+)', sample_field)
if idx_match:
info['index_i7'] = idx_match.group(1)
info['index_i5'] = idx_match.group(2)
# 剩余部分作为样本名
info['sample_name'] = sample_field.split('_')[0] if '_' in sample_field else sample_field
else:
info['sample_name'] = sample_field
else:
info['sample_name'] = sample_field
# 提取Lane编号
for part in parts:
if part.startswith('L') and len(part) == 4 and part[1:].isdigit():
info['lane'] = part
break
# 提取Read方向
for part in parts:
if part in ['R1', 'R2']:
info['read_direction'] = part
break
return info
# 示例用法
if __name__ == '__main__':
test_files = [
'SampleA_GTAGAGGA-CTCTCTAT_L001_R1_001.fastq.gz',
'MISEQ01_20231017_SampleA_GTAGAGGA-CTCTCTAT_L001_R1_001.fastq.gz',
]
for f in test_files:
result = parse_fastq_filename(f)
print(result)
这个函数覆盖了最常见的两种格式。实际项目中,我遇到过一些测序公司习惯在文件名里附加项目号(比如Proj001_),这时你只需要在parts切片那里多判断一下。记住核心逻辑:不管格式怎么变,仪器、Run、Lane、索引这四个字段一定在文件名里出现一次。