名称: anndata 描述: “操作AnnData对象用于单细胞基因组学。加载/保存.h5ad文件,管理obs/var元数据,图层,嵌入(PCA/UMAP),拼接数据集,用于scRNA-seq工作流。”
AnnData
概述
AnnData(注释数据)是Python中用于存储和操作注释数据矩阵的标准,特别是在单细胞基因组学中。使用AnnData对象进行数据创建、操作、文件I/O、拼接和内存高效工作流。
核心能力
1. 创建和结构化AnnData对象
从各种数据源创建AnnData对象,并组织多维注释。
基本创建:
import anndata as ad
import numpy as np
from scipy.sparse import csr_matrix
# 从密集或稀疏数组
counts = np.random.poisson(1, size=(100, 2000))
adata = ad.AnnData(counts)
# 使用稀疏矩阵(内存高效)
counts = csr_matrix(np.random.poisson(1, size=(100, 2000)), dtype=np.float32)
adata = ad.AnnData(counts)
带元数据:
import pandas as pd
obs_meta = pd.DataFrame({
'cell_type': pd.Categorical(['B', 'T', 'Monocyte'] * 33 + ['B']),
'batch': ['batch1'] * 50 + ['batch2'] * 50
})
var_meta = pd.DataFrame({
'gene_name': [f'Gene_{i}' for i in range(2000)],
'highly_variable': np.random.choice([True, False], 2000)
})
adata = ad.AnnData(counts, obs=obs_meta, var=var_meta)
理解结构:
- X: 主要数据矩阵(观测×变量)
- obs: 行(观测)注释作为DataFrame
- var: 列(变量)注释作为DataFrame
- obsm: 多维观测注释(例如,PCA、UMAP坐标)
- varm: 多维变量注释(例如,基因载荷)
- layers: 替代数据矩阵,与X维度相同
- uns: 非结构化元数据字典
- obsp/varp: 成对关系矩阵(图)
2. 添加注释和图层
在单个对象内组织不同数据表示和元数据。
细胞级元数据(obs):
adata.obs['n_genes'] = (adata.X > 0).sum(axis=1)
adata.obs['total_counts'] = adata.X.sum(axis=1)
adata.obs['condition'] = pd.Categorical(['control', 'treated'] * 50)
基因级元数据(var):
adata.var['highly_variable'] = gene_variance > threshold
adata.var['chromosome'] = pd.Categorical(['chr1', 'chr2', ...])
嵌入(obsm/varm):
# 降维结果
adata.obsm['X_pca'] = pca_coordinates # 形状: (n_obs, n_components)
adata.obsm['X_umap'] = umap_coordinates # 形状: (n_obs, 2)
adata.obsm['X_tsne'] = tsne_coordinates
# 基因载荷
adata.varm['PCs'] = principal_components # 形状: (n_vars, n_components)
替代数据表示(layers):
# 存储多个版本
adata.layers['counts'] = raw_counts
adata.layers['log1p'] = np.log1p(adata.X)
adata.layers['scaled'] = (adata.X - mean) / std
非结构化元数据(uns):
# 分析参数
adata.uns['preprocessing'] = {
'normalization': 'TPM',
'min_genes': 200,
'date': '2024-01-15'
}
# 结果
adata.uns['pca'] = {'variance_ratio': variance_explained}
3. 子集和视图
通过视图和副本高效子集数据,同时管理内存。
子集操作:
# 通过观测/变量名称
subset = adata[['Cell_1', 'Cell_10'], ['Gene_5', 'Gene_1900']]
# 通过布尔掩码
b_cells = adata[adata.obs.cell_type == 'B']
high_quality = adata[adata.obs.n_genes > 200]
# 通过位置
first_cells = adata[:100, :]
top_genes = adata[:, :500]
# 组合条件
filtered = adata[
(adata.obs.batch == 'batch1') & (adata.obs.n_genes > 200),
adata.var.highly_variable
]
理解视图:
- 子集默认返回视图(内存高效,与原始对象共享数据)
- 修改视图会影响原始对象
- 使用
adata.is_view检查 - 使用
.copy()转换为独立副本
# 视图(内存高效)
subset = adata[adata.obs.condition == 'treated']
print(subset.is_view) # True
# 独立副本
subset_copy = adata[adata.obs.condition == 'treated'].copy()
print(subset_copy.is_view) # False
4. 文件I/O和备份模式
高效读写数据,适用于内存有限环境。
写入数据:
# 标准格式带压缩
adata.write('results.h5ad', compression='gzip')
# 替代格式
adata.write_zarr('results.zarr') # 用于云存储
adata.write_loom('results.loom') # 用于兼容性
adata.write_csvs('results/') # 作为CSV文件
读取数据:
# 加载到内存
adata = ad.read_h5ad('results.h5ad')
# 备份模式(磁盘备份,内存高效)
adata = ad.read_h5ad('large_file.h5ad', backed='r')
print(adata.isbacked) # True
print(adata.filename) # 文件路径
# 完成后关闭文件连接
adata.file.close()
从其他格式读取:
# 10X格式
adata = ad.read_mtx('matrix.mtx')
# CSV
adata = ad.read_csv('data.csv')
# Loom
adata = ad.read_loom('data.loom')
使用备份模式:
# 读取备份模式用于大文件
adata = ad.read_h5ad('large_dataset.h5ad', backed='r')
# 分块处理
for chunk in adata.chunk_X(chunk_size=1000):
result = process_chunk(chunk)
# 如需加载到内存
adata_memory = adata.to_memory()
5. 拼接多个数据集
组合多个AnnData对象,控制数据合并方式。
基本拼接:
# 拼接观测(最常见)
combined = ad.concat([adata1, adata2, adata3], axis=0)
# 拼接变量(罕见)
combined = ad.concat([adata1, adata2], axis=1)
连接策略:
# 内连接:仅共享变量(无缺失数据)
combined = ad.concat([adata1, adata2], join='inner')
# 外连接:所有变量(用0填充缺失)
combined = ad.concat([adata1, adata2], join='outer')
跟踪数据来源:
# 添加来源标签
combined = ad.concat(
[adata1, adata2, adata3],
label='dataset',
keys=['exp1', 'exp2', 'exp3']
)
# 创建combined.obs['dataset'],值为'exp1', 'exp2', 'exp3'
# 使重复索引唯一
combined = ad.concat(
[adata1, adata2],
keys=['batch1', 'batch2'],
index_unique='-'
)
# 细胞名称变为: Cell_0-batch1, Cell_0-batch2, 等
元数据合并策略:
# merge=None: 排除变量注释(默认)
combined = ad.concat([adata1, adata2], merge=None)
# merge='same': 仅保留相同注释
combined = ad.concat([adata1, adata2], merge='same')
# merge='first': 使用首次出现
combined = ad.concat([adata1, adata2], merge='first')
# merge='unique': 保留单一值注释
combined = ad.concat([adata1, adata2], merge='unique')
完整示例:
# 加载批次
batch1 = ad.read_h5ad('batch1.h5ad')
batch2 = ad.read_h5ad('batch2.h5ad')
batch3 = ad.read_h5ad('batch3.h5ad')
# 拼接并完全跟踪
combined = ad.concat(
[batch1, batch2, batch3],
axis=0,
join='outer', # 保留所有基因
merge='first', # 使用第一批次的注释
label='batch_id', # 跟踪来源
keys=['b1', 'b2', 'b3'], # 自定义标签
index_unique='-' # 使细胞名称唯一
)
6. 数据转换和提取
在AnnData和其他格式之间转换,实现互操作性。
转换为DataFrame:
# 转换X为DataFrame
df = adata.to_df()
# 转换特定图层
df = adata.to_df(layer='log1p')
提取向量:
# 从数据或注释获取1D数组
gene_expression = adata.obs_vector('Gene_100')
cell_metadata = adata.obs_vector('n_genes')
转置:
# 交换观测和变量
transposed = adata.T
7. 内存优化
高效处理大型数据集的策略。
使用稀疏矩阵:
from scipy.sparse import csr_matrix
# 检查稀疏性
density = (adata.X != 0).sum() / adata.X.size
if density < 0.3: # 少于30%非零值
adata.X = csr_matrix(adata.X)
转换字符串为分类:
# 自动转换
adata.strings_to_categoricals()
# 手动转换(更可控)
adata.obs['cell_type'] = pd.Categorical(adata.obs['cell_type'])
使用备份模式:
# 读取但不加载到内存
adata = ad.read_h5ad('large_file.h5ad', backed='r')
# 处理子集
subset = adata[:1000, :500].copy() # 仅此子集在内存中
分块处理:
# 分块处理数据
results = []
for chunk in adata.chunk_X(chunk_size=1000):
result = expensive_computation(chunk)
results.append(result)
常见工作流
单细胞RNA-seq分析
从加载到分析的完整工作流:
import anndata as ad
import numpy as np
import pandas as pd
# 1. 加载数据
adata = ad.read_mtx('matrix.mtx')
adata.obs_names = pd.read_csv('barcodes.tsv', header=None)[0]
adata.var_names = pd.read_csv('genes.tsv', header=None)[0]
# 2. 质量控制
adata.obs['n_genes'] = (adata.X > 0).sum(axis=1)
adata.obs['total_counts'] = adata.X.sum(axis=1)
adata = adata[adata.obs.n_genes > 200]
adata = adata[adata.obs.total_counts < 10000]
# 3. 过滤基因
min_cells = 3
adata = adata[:, (adata.X > 0).sum(axis=0) >= min_cells]
# 4. 存储原始计数
adata.layers['counts'] = adata.X.copy()
# 5. 标准化
adata.X = adata.X / adata.obs.total_counts.values[:, None] * 1e4
adata.X = np.log1p(adata.X)
# 6. 特征选择
gene_var = adata.X.var(axis=0)
adata.var['highly_variable'] = gene_var > np.percentile(gene_var, 90)
# 7. 降维(外部工具示例)
# adata.obsm['X_pca'] = compute_pca(adata.X)
# adata.obsm['X_umap'] = compute_umap(adata.obsm['X_pca'])
# 8. 保存结果
adata.write('analyzed.h5ad', compression='gzip')
批次整合
组合多个实验批次:
# 加载批次
batches = [ad.read_h5ad(f'batch_{i}.h5ad') for i in range(3)]
# 拼接并跟踪
combined = ad.concat(
batches,
axis=0,
join='outer',
label='batch',
keys=['batch_0', 'batch_1', 'batch_2'],
index_unique='-'
)
# 添加批次为数值用于校正算法
combined.obs['batch_numeric'] = combined.obs['batch'].cat.codes
# 执行批次校正(外部工具)
# corrected_pca = run_harmony(combined.obsm['X_pca'], combined.obs['batch'])
# combined.obsm['X_pca_corrected'] = corrected_pca
# 保存整合数据
combined.write('integrated.h5ad', compression='gzip')
内存高效大型数据集处理
处理内存无法容纳的大型数据集:
# 读取备份模式
adata = ad.read_h5ad('huge_dataset.h5ad', backed='r')
# 分块计算统计量
total = 0
for chunk in adata.chunk_X(chunk_size=1000):
total += chunk.sum()
mean_expression = total / (adata.n_obs * adata.n_vars)
# 处理子集
high_quality_cells = adata.obs.n_genes > 1000
subset = adata[high_quality_cells, :].copy()
# 关闭文件
adata.file.close()
最佳实践
数据组织
- 为不同表示使用图层:在单独图层中存储原始计数、标准化、对数转换和缩放数据
- 为多维数据使用obsm/varm:嵌入、载荷和其他矩阵样注释
- 为元数据使用uns:分析参数、日期、版本信息
- 为效率使用分类:转换重复字符串为分类类型
子集
- 理解视图与副本:子集默认返回视图;需要独立时使用
.copy() - 高效链接条件:在单个子集操作中组合布尔掩码
- 子集后验证:检查维度和数据完整性
文件I/O
- 使用压缩:写入h5ad文件时始终使用
compression='gzip' - 选择正确格式:H5AD用于通用,Zarr用于云存储,Loom用于兼容性
- 关闭备份文件:完成后始终关闭文件连接
- 为大型文件使用备份模式:如非必要,不要加载所有内容到内存
拼接
- 选择适当连接:内连接用于完整案例,外连接以保留所有特征
- 跟踪来源:使用
label和keys跟踪数据来源 - 处理重复:使用
index_unique使观测名称唯一 - 选择合并策略:为变量注释选择适当合并策略
内存管理
- 使用稀疏矩阵:用于非零值少于30%的数据
- 转换为分类:用于重复字符串值
- 分块处理:用于非常大的矩阵操作
- 使用备份模式:使用
backed='r'读取大型文件
命名约定
遵循这些约定以保持一致:
- 嵌入:
X_pca,X_umap,X_tsne - 图层:描述性名称如
counts,log1p,scaled - 观测:使用snake_case如
cell_type,n_genes,total_counts - 变量:使用snake_case如
highly_variable,gene_name
参考文档
有关详细API信息、使用模式和故障排除,请参阅references/目录中的全面参考文件:
-
api_reference.md:完整的API文档,包括所有类、方法和函数,带使用示例。使用
grep -r "pattern" references/api_reference.md搜索特定函数或参数。 -
workflows_best_practices.md:常见任务的详细工作流(单细胞分析、批次整合、大型数据集),内存管理最佳实践、数据组织和常见陷阱。使用
grep -r "pattern" references/workflows_best_practices.md搜索特定工作流。 -
concatenation_guide.md:拼接策略综合指南,连接类型、合并策略、来源跟踪和拼接问题故障排除。使用
grep -r "pattern" references/concatenation_guide.md搜索拼接模式。
何时加载参考
在以下情况下将参考文件加载到上下文:
- 实现具有特定合并策略的复杂拼接
- 故障排除错误或意外行为
- 优化大型数据集内存使用
- 实现完整分析工作流
- 理解特定API方法的细微差别
在不加载的情况下搜索参考:
# 示例:搜索备份模式信息
grep -r "backed mode" references/
常见错误模式
内存错误
问题:“MemoryError: Unable to allocate array” 解决方案:使用备份模式、稀疏矩阵或分块处理
维度不匹配
问题:“ValueError: operands could not be broadcast together” 解决方案:在拼接中使用外连接或在操作前对齐索引
视图修改
问题:“ValueError: assignment destination is read-only”
解决方案:修改前使用.copy()将视图转换为副本
文件已打开
问题:“OSError: Unable to open file (file is already open)”
解决方案:使用adata.file.close()关闭先前文件连接