第4章:数据读取——从原始文件到Seurat对象
说起单细胞数据读取,很多朋友上来就问:该读什么格式?我刚开始那会儿也懵,10X的、Smart-seq2的、还有各种奇奇怪怪的H5文件。其实核心就一句话:把原始数据塞进Seurat认识的结构里。
这一章,我们就来聊聊怎么把不同平台的数据变成Seurat对象。嗯,这可是所有后续分析的基础,必须整明白。
4.1 10X Genomics格式:最常用的“三位一体”
10X平台是目前单细胞数据的主流来源。它的原始输出是三个文件,缺一不可。我个人习惯管它叫“三件套”。
- barcodes.tsv:细胞条形码列表,说白了就是每个细胞的“身份证号”。
- features.tsv:基因特征列表,早期版本叫genes.tsv,包括基因ID和基因名两列。
- matrix.mtx:表达量矩阵,Market Exchange格式,稀疏矩阵,只存储非零值。
读取方法很简单:
library(Seurat)
# 指定数据目录(包含三个文件的文件夹)
data_dir <- "path/to/filtered_feature_bc_matrix/"
# 读取10X数据
counts <- Read10X(data.dir = data_dir)
# 创建Seurat对象
seurat_obj <- CreateSeuratObject(counts = counts, project = "my_project")
小提示:Read10X函数会默认读取当前目录下名为“filtered_feature_bc_matrix”的文件夹。你也可以直接用绝对路径,这样更稳妥。
我在项目中遇到的问题:有一次数据目录下有两个子文件夹,一个叫“raw”,一个叫“filtered”。我一时大意读了raw,结果分析出来的细胞数量多了好几倍。嗯,记得要用filtered的,那个才是质检后的高质量细胞。
4.2 Smart-seq2格式:传统表达矩阵
Smart-seq2是另一种常见技术。它的数据通常是一个基因×细胞的表达矩阵,CSV或TSV格式。说白了,就是一个普通的表格文件。
读取方法:
# 读取表达矩阵(行是基因,列是细胞)
expr_matrix <- read.table("expression_matrix.tsv",
header = TRUE,
row.names = 1,
sep = "\t")
# 直接创建Seurat对象
seurat_obj <- CreateSeuratObject(counts = expr_matrix,
project = "smartseq2_project")
这里要注意一点:read.table的行名必须是基因名,列名必须是细胞ID。数据框的内容就是表达量。
我曾经踩过的坑:Smart-seq2的数据有时候会包含重复的基因名。如果你忘了去重,Seurat会报错。我的建议是:读数据之前先用
duplicated()检查一下。
4.3 其他格式怎么办?
除了上面两种,实际项目中还会遇到一些“非主流”格式。别慌,Seurat都给你准备好了。
| 格式 | 读取函数 | 说明 |
|---|---|---|
| Drop-seq | ReadDropSeq() | DGE格式,类似10X但文件结构不同 |
| BD Rhapsody | ReadBD() | BD平台的数据,文件后缀名不一样 |
| H5 (HDF5) | Read10X_h5() | 10X的H5格式,一个文件打包所有数据 |
| STARsolo | ReadSTARsolo() | STAR比对工具的输出 |
一句话总结:大多数主流平台的专用函数,都内置在Seurat包中。查一下文档就能找到对应的函数名。
4.4 读完之后,先看一眼数据
数据读进来后,我通常会做两件事:
- 检查维度:看看有多少个基因,多少细胞,心里有个数。
- 看看元数据:Seurat对象自动给你加了nCount_RNA和nFeature_RNA两列,就是每个细胞的UMI总数和基因数。
# 查看Seurat对象的结构
seurat_obj
# 查看元数据
head(seurat_obj@meta.data)
# 查看表达矩阵的维度
dim(GetAssayData(seurat_obj, slot = "counts"))
# 检查细胞数
ncol(seurat_obj)
# 检查基因数
nrow(seurat_obj)
你想想看,如果一次读进来10万个细胞,那后续的计算量可不小。我遇到过一个项目,原始数据包含50万细胞,靠单机根本跑不动,最后只能用降采样+并行处理。所以一开始就要对数据规模有个预判。
4.5 一点避坑指南
- 文件名大小写:Linux系统上大小写敏感,barcodes.tsv和Barcodes.tsv是两个文件。
- 路径分隔符:Windows用反斜杠\,但R里建议用正斜杠/,或者用双反斜杠\\。
- 内存占用:几千个细胞的矩阵还好,几万细胞的话,读取时会消耗大量内存。建议用2G以上的内存来跑。
- 重复行名:如果你用的是自定义矩阵,记得确保基因名唯一。重复名称会导致CreateSeuratObject报错。
一个小技巧:如果你需要反复读取同一个数据集,可以先把Seurat对象保存为RDS文件,下次直接用
readRDS()加载。速度能快好几倍。
数据读取这一步其实不算复杂。核心就是找到正确的文件,用对的函数,然后看一眼元数据。后面的过滤、标准化、降维、聚类,才是真正考验功夫的地方。不过,数据读不对,后面全白搭。所以,嗯,这一步务必认真对待。