数据获取与质量评估——打好基础比什么都重要
说实话,空间转录组分析里最容易被低估的环节,就是数据获取和质量评估。我见过不少人一上来就急着跑下游分析,结果花了几周时间,最后发现是数据本身有问题,白白浪费了精力。
2.1 主流数据来源,你得知道去哪找
目前空间转录组数据主要来自两个方向:一个是平台公开的数据,一个是自己跑实验。绝大多数教学和研究用的都是公开数据,常用的有这么几个:
| 数据来源 | 平台/格式 | 特点 |
|---|---|---|
| 10x Visium | SPATIAL, H5, 图像 | 市面上最常见,社区资源丰富 |
| Slide-seq | Segmentation, beads | 分辨率高,但基因捕获效率略低 |
| ST (Spatial Transcriptomics) | 原始测序数据 | 早期平台,现在用得少了 |
| MERFISH / seqFISH | 成像数据 | 单细胞分辨率,通量有限 |
我个人习惯首选 10x Visium 数据,因为它的教程和工具链最成熟。你到 10x Genomics 官网的 Datasets 板块,能找到大量示例数据,包括人类乳腺癌、小鼠脑切片这些经典样本。
SpaceRanger 输出,省时省力。格式一般是 .h5 和 .tif 图像文件夹。
2.2 数据落地——把数据拉下来并看懂结构
假设你找到了一个 Visium 数据集,用 wget 下载后,文件夹结构大概是这样:
# 典型的 SpaceRanger 输出结构
sample345/
├── outs/
│ ├── filtered_feature_bc_matrix.h5
│ ├── filtered_feature_bc_matrix/
│ │ ├── barcodes.tsv.gz
│ │ ├── features.tsv.gz
│ │ └── matrix.mtx.gz
│ ├── spatial/
│ │ ├── tissue_positions_list.csv
│ │ ├── scalefactors_json.json
│ │ └── tissue_hires_image.png
│ └── analysis/
│ ├── clustering/
│ └── ...
这里面最关键的是三个文件:
filtered_feature_bc_matrix.h5—— 基因表达矩阵,相当于单细胞的表达矩阵,但多了 spot 坐标tissue_positions_list.csv—— 每个 spot 的物理坐标 (x, y),组织在不在组织区域 (in_tissue=1/0)scalefactors_json.json—— 图像缩放参数,用来把 spot 坐标映射到组织图像上
tissue_positions_list.csv 里全是 in_tissue=0,说白了就是组织区域外的背景点。这种情况直接过滤掉就行,不然下游分析全乱了。
2.3 质量评估——别急着建模
数据一到手,我建议先做三件事:
- 看细胞/spot 数量——是不是太少?一般 Visium 一个切片应该有 3000~5000 个 spot
- 看基因检出率——中位数基因数太低(比如低于 500),可能组织处理有问题
- 看组织图像——有没有气泡、褶皱、坏死区域
我常用 Scanpy 或 Squidpy 做初步质控。举个简单的例子,用 Python 读取 H5 数据:
import scanpy as sc
import pandas as pd
# 读取数据
adata = sc.read_10x_h5('outs/filtered_feature_bc_matrix.h5')
adata.var_names_make_unique()
# 简单质控指标
sc.pp.calculate_qc_metrics(adata, percent_top=None, log1p=False)
print(adata.obs['n_genes_by_counts'].describe())
# 过滤低质量 spot
sc.pp.filter_cells(adata, min_genes=200)
sc.pp.filter_genes(adata, min_cells=3)
print(f"过滤后剩余 {adata.n_obs} 个 spot,{adata.n_vars} 个基因")
结果输出大概长这样:
count 4932.000000
mean 1567.340000
std 413.210000
min 102.000000
25% 1289.000000
50% 1593.000000
75% 1856.000000
max 2873.000000
Name: n_genes_by_counts, dtype: float64
过滤后剩余 4890 个 spot,18543 个基因
这里有个细节:min_genes=200 是单细胞分析的标准阈值,空间转录组可以适当放低到 100。为什么?因为 spot 可能比细胞大,包含多个细胞核碎片,基因检出率天然低一些。
- 每个 spot 至少 200 个 UMI(Unique Molecular Identifier)
- 每个 spot 至少 100 个基因
- 线粒体基因比例不超过 20%
- 组织区域外的 spot 直接丢弃
2.4 坐标对齐——让基因和空间位置对上
光有表达矩阵还不够,你得把基因表达数据“贴”到组织图像上。这一步的核心是 tissue_positions_list.csv 这个文件。
我用一个简单的例子说明怎么合并坐标信息:
import pandas as pd
import scanpy as sc
# 读取坐标
coords = pd.read_csv(
'outs/spatial/tissue_positions_list.csv',
header=None,
names=['barcode', 'in_tissue', 'array_row', 'array_col', 'pxl_row_in_fullres', 'pxl_col_in_fullres']
)
# 只保留组织区域的 spot
coords_tissue = coords[coords['in_tissue'] == 1].copy()
# 把坐标加入 adata
adata.obs = adata.obs.join(
coords_tissue.set_index('barcode')[['pxl_row_in_fullres', 'pxl_col_in_fullres']]
)
# 添加成 spatial 标准格式
adata.obsm['spatial'] = adata.obs[['pxl_col_in_fullres', 'pxl_row_in_fullres']].values
print(f"添加了 {adata.obsm['spatial'].shape[0]} 个 spot 的空间坐标")
2.5 可视化质控——一张图胜过千行代码
我觉得质控中最直观的一步,就是把 UMI 数、基因数用颜色映射到组织图像上。看一眼就知道哪些区域有问题。
import scanpy as sc
import matplotlib.pyplot as plt
# 用 Squidpy 或 Scanpy 绘图
sc.pl.spatial(adata, img_key='hires',
color=['n_genes_by_counts', 'total_counts'],
crop_coord=[1000, 6000, 1000, 6000],
show=True)
你想象一下,正常组织应该是均匀分布的颜色。如果某个区域突然很暗(基因数极低),那可能是组织折叠、气泡,或者坏死。我以前遇到过一种情况:样本边缘一圈 spot 的基因数只有中心区域的 1/3,后来发现是组织切片时边缘损伤了。
2.6 本章知识结构总览
2.7 常见坑和我的解决建议
做多了你就会发现,数据质控这一步往往比下游建模更花时间。我总结几个常见问题:
我曾经遇到过边缘 spot 的 UMI 数只有中心的 1/10。解决方案是做一个
total_counts 阈值过滤,比如只保留 UMI 数 > 500 的 spot。
有时候下载的数据包
scalefactors_json.json 里的 tissue_hires_scalef 参数不对,导致 spot 画在图像外面。我建议每次都手动检查一下第一个 spot 的像素坐标是否在图像尺寸范围内。
barcode,有人用 cell_id,还有用 spot 的。搞个标准化映射,能省去很多调试时间。
2.8 质控后的标准输出格式
完成所有步骤后,你应该得到一个 AnnData 对象,里面包含:
adata.X—— 过滤后的表达矩阵(spot × gene)adata.obs—— spot 级别的元数据(总 UMI、基因数、线粒体比例等)adata.obsm['spatial']—— 像素坐标 (N×2 数组)adata.uns['spatial']—— 图像和缩放参数(可选)
保存成标准格式,方便后续直接读取:
# 保存质控后的数据
adata.write('qc_pass.h5ad')
# 下次直接读取
adata = sc.read('qc_pass.h5ad')
print(adata)
# AnnData object with n_obs × n_vars = 4890 × 18543
# obs: 'n_genes_by_counts', 'total_counts', 'pct_counts_mt'
# obsm: 'spatial'
# uns: 'spatial'
看到这个输出,你就可以放心地进入下一步了——构建细胞邻域图,开始特征建模。记住,数据质量决定了分析的天花板,这一步花再长时间都值得。