单细胞数据的细胞注释一直是个老大难
问题,这一步非常关键,以前一直是手工注释。🙊
最近发现了一个AI
辅助的注释工具,非常不错,原作者也是向我毛遂自荐,用了一下确实不错。👍
大家可以试一试,mLLMCelltype
。🤩
mLLMCelltype
是一个迭代式多大语言模型(Multi-LLM
)共识框架,专为单细胞RNA测序数据的细胞类型注释而设计。😘
通过利用多种大语言模型(如GPT
、Claude
、Gemini
、Grok
、DeepSeek
、Qwen
等)的互补优势,该框架显著提高了注释准确性,同时提供透明的不确定性量化。🧐
# 从GitHub安装
devtools::install_github("cafferychen777/mLLMCelltype", subdir = "R")
# 从PyPI安装
pip install mllmcelltype
# 或从GitHub安装
pip install git+https://github.com/cafferychen777/mLLMCelltype.git
import scanpy as sc
import pandas as pd
from mllmcelltype import annotate_clusters, setup_logging, interactive_consensus_annotation
import os
# 设置日志
setup_logging()
# 加载数据
adata = sc.read_h5ad('your_data.h5ad')
# 检查是否已计算leiden聚类,如果没有,则计算
if'leiden'notin adata.obs.columns:
print("计算leiden聚类...")
# 确保数据已预处理(标准化、对数转换等)
if'log1p'notin adata.uns:
sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)
# 如果尚未计算PCA,则计算
if'X_pca'notin adata.obsm:
sc.pp.highly_variable_genes(adata, min_mean=0.0125, max_mean=3, min_disp=0.5)
sc.pp.pca(adata, use_highly_variable=True)
# 计算邻居图和leiden聚类
sc.pp.neighbors(adata, n_neighbors=10, n_pcs=30)
sc.tl.leiden(adata, resolution=0.8)
print(f"leiden聚类完成,共有{len(adata.obs['leiden'].cat.categories)}个聚类")
# 运行差异表达分析获取标记基因
sc.tl.rank_genes_groups(adata, 'leiden', method='wilcoxon')
# 为每个聚类提取标记基因
marker_genes = {}
for i in range(len(adata.obs['leiden'].cat.categories)):
# 为每个聚类提取前10个基因
genes = [adata.uns['rank_genes_groups']['names'][str(i)][j] for j in range(10)]
marker_genes[str(i)] = genes
# 重要提示:确保使用基因符号(如KCNJ8, PDGFRA)而不是Ensembl ID(如ENSG00000176771)
# 如果您的AnnData对象存储的是Ensembl ID,请先将其转换为基因符号:
# 示例:
# if 'Gene' in adata.var.columns: # 检查var数据框中是否有基因符号
# gene_name_dict = dict(zip(adata.var_names, adata.var['Gene']))
# marker_genes = {cluster: [gene_name_dict.get(gene_id, gene_id) for gene_id in genes]
# for cluster, genes in marker_genes.items()}
# 设置您想要使用的提供商的API密钥
# 您至少需要一个与计划使用的模型相对应的API密钥
os.environ["OPENAI_API_KEY"] = "your-openai-api-key"# GPT模型所需
os.environ["ANTHROPIC_API_KEY"] = "your-anthropic-api-key"# Claude模型所需
os.environ["GEMINI_API_KEY"] = "your-gemini-api-key"# Gemini模型所需
os.environ["QWEN_API_KEY"] = "your-qwen-api-key"# 通义千问模型所需
# 其他可选模型
# os.environ["DEEPSEEK_API_KEY"] = "your-deepseek-api-key" # DeepSeek模型所需
# os.environ["ZHIPU_API_KEY"] = "your-zhipu-api-key" # 智谱GLM模型所需
# os.environ["STEPFUN_API_KEY"] = "your-stepfun-api-key" # Step模型所需
# os.environ["MINIMAX_API_KEY"] = "your-minimax-api-key" # MiniMax模型所需
# 使用多个模型运行共识注释
consensus_results = interactive_consensus_annotation(
marker_genes=marker_genes,
species="human",
tissue="blood",
models=["gpt-4o", "claude-3-7-sonnet-20250219", "gemini-1.5-pro", "qwen-max-2025-01-25"],
consensus_threshold=0.7, # 调整共识一致性阈值
max_discussion_rounds=3# 模型间讨论的最大轮数
)
# 从字典中获取最终共识注释
final_annotations = consensus_results["consensus"]
# 将共识注释添加到AnnData对象
adata.obs['consensus_cell_type'] = adata.obs['leiden'].astype(str).map(final_annotations)
# 将不确定性指标添加到AnnData对象
adata.obs['consensus_proportion'] = adata.obs['leiden'].astype(str).map(consensus_results["consensus_proportion"])
adata.obs['entropy'] = adata.obs['leiden'].astype(str).map(consensus_results["entropy"])
# 重要提示:确保在可视化前已计算UMAP坐标
# 如果您的AnnData对象中没有UMAP坐标,请计算:
if'X_umap'notin adata.obsm:
print("计算UMAP坐标...")
# 确保已计算邻居图
if'neighbors'notin adata.uns:
sc.pp.neighbors(adata, n_neighbors=10, n_pcs=30)
sc.tl.umap(adata)
print("UMAP坐标计算完成")
# 使用增强美学效果可视化结果
# 基础可视化
sc.pl.umap(adata, color='consensus_cell_type', legend_loc='right', frameon=True, title='mLLMCelltype共识注释')
# 更多自定义可视化
import matplotlib.pyplot as plt
# 设置图形尺寸和样式
plt.rcParams['figure.figsize'] = (10, 8)
plt.rcParams['font.size'] = 12
# 创建更适合发表的UMAP图
fig, ax = plt.subplots(1, 1, figsize=(12, 10))
sc.pl.umap(adata, color='consensus_cell_type', legend_loc='on data',
frameon=True, title='mLLMCelltype共识注释',
palette='tab20', size=50, legend_fontsize=12,
legend_fontoutline=2, ax=ax)
# 可视化不确定性指标
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 7))
sc.pl.umap(adata, color='consensus_proportion', ax=ax1, title='共识比例',
cmap='viridis', vmin=0, vmax=1, size=30)
sc.pl.umap(adata, color='entropy', ax=ax2, title='注释不确定性(香农熵)',
cmap='magma', vmin=0, size=30)
plt.tight_layout()
# 加载所需包
library(mLLMCelltype)
library(Seurat)
library(dplyr)
library(ggplot2)
library(cowplot) # 添加用于 plot_grid
# 加载预处理的Seurat对象
pbmc <- readRDS("your_seurat_object.rds")
# 为每个聚类寻找标记基因
pbmc_markers <- FindAllMarkers(pbmc,
only.pos = TRUE,
min.pct = 0.25,
logfc.threshold = 0.25)
# 使用多个LLM模型运行LLMCelltype注释
consensus_results <- interactive_consensus_annotation(
input = pbmc_markers,
tissue_name = "human PBMC", # 提供组织上下文
models = c(
"claude-3-7-sonnet-20250219", # Anthropic
"gpt-4o", # OpenAI
"gemini-1.5-pro", # Google
"qwen-max-2025-01-25"# Alibaba
),
api_keys = list(
anthropic = "your-anthropic-key",
openai = "your-openai-key",
gemini = "your-google-key",
qwen = "your-qwen-key"
),
top_gene_count = 10,
controversy_threshold = 0.7
)
# 将注释添加到Seurat对象
# 从 consensus_results$final_annotations 获取细胞类型注释
cluster_to_celltype_map <- consensus_results$final_annotations
# 创建新的细胞类型标识符列
cell_types <- as.character(Idents(pbmc))
for (cluster_id in names(cluster_to_celltype_map)) {
cell_types[cell_types == cluster_id] <- cluster_to_celltype_map[[cluster_id]]
}
# 将细胞类型注释添加到Seurat对象
pbmc$cell_type <- cell_types
# 添加不确定性指标
# 提取包含指标的详细共识结果
consensus_details <- consensus_results$initial_results$consensus_results
# 为每个聚类创建包含指标的数据框
uncertainty_metrics <- data.frame(
cluster_id = names(consensus_details),
consensus_proportion = sapply(consensus_details, function(res) res$consensus_proportion),
entropy = sapply(consensus_details, function(res) res$entropy)
)
# 为每个细胞添加不确定性指标
pbmc$consensus_proportion <- uncertainty_metrics$consensus_proportion[match(current_clusters, uncertainty_metrics$cluster_id)]
pbmc$entropy <- uncertainty_metrics$entropy[match(current_clusters, uncertainty_metrics$cluster_id)]
# 使用SCpubr进行出版级可视化
if (!requireNamespace("SCpubr", quietly = TRUE)) {
remotes::install_github("enblacar/SCpubr")
}
library(SCpubr)
# 基础UMAP可视化(默认设置)
pdf("pbmc_basic_annotations.pdf", width=8, height=6)
SCpubr::do_DimPlot(sample = pbmc,
group.by = "cell_type",
label = TRUE,
legend.position = "right") +
ggtitle("mLLMCelltype共识注释")
dev.off()
# 更多自定义可视化(增强样式)
pdf("pbmc_custom_annotations.pdf", width=8, height=6)
SCpubr::do_DimPlot(sample = pbmc,
group.by = "cell_type",
label = TRUE,
label.box = TRUE,
legend.position = "right",
pt.size = 1.0,
border.size = 1,
font.size = 12) +
ggtitle("mLLMCelltype共识注释") +
theme(plot.title = element_text(hjust = 0.5))
dev.off()
# 使用增强型SCpubr图表可视化不确定性指标
# 获取细胞类型并创建命名的颜色调色板
cell_types <- unique(pbmc$cell_type)
color_palette <- viridis::viridis(length(cell_types))
names(color_palette) <- cell_types
# 使用SCpubr的细胞类型注释
p1 <- SCpubr::do_DimPlot(sample = pbmc,
group.by = "cell_type",
label = TRUE,
legend.position = "bottom", # 将图例放在底部
pt.size = 1.0,
label.size = 4, # 较小的标签字体大小
label.box = TRUE, # 为标签添加背景框以提高可读性
repel = TRUE, # 使标签相互排斥以避免重叠
colors.use = color_palette,
plot.title = "Cell Type") +
theme(plot.title = element_text(hjust = 0.5, margin = margin(b = 15, t = 10)),
legend.text = element_text(size = 8),
legend.key.size = unit(0.3, "cm"),
plot.margin = unit(c(0.8, 0.8, 0.8, 0.8), "cm"))
# 使用SCpubr的共识比例特征图
p2 <- SCpubr::do_FeaturePlot(sample = pbmc,
features = "consensus_proportion",
order = TRUE,
pt.size = 1.0,
enforce_symmetry = FALSE,
legend.title = "Consensus",
plot.title = "Consensus Proportion",
sequential.palette = "YlGnBu", # 使用黄-绿-蓝渐变色,符合Nature Methods标准
sequential.direction = 1, # 从浅到深方向
min.cutoff = min(pbmc$consensus_proportion), # 设置最小值
max.cutoff = max(pbmc$consensus_proportion), # 设置最大值
na.value = "lightgrey") + # 缺失值的颜色
theme(plot.title = element_text(hjust = 0.5, margin = margin(b = 15, t = 10)),
plot.margin = unit(c(0.8, 0.8, 0.8, 0.8), "cm"))
# 使用SCpubr的Shannon熵特征图
p3 <- SCpubr::do_FeaturePlot(sample = pbmc,
features = "entropy",
order = TRUE,
pt.size = 1.0,
enforce_symmetry = FALSE,
legend.title = "Entropy",
plot.title = "Shannon Entropy",
sequential.palette = "OrRd", # 使用橙-红渐变色,符合Nature Methods标准
sequential.direction = -1, # 从深到浅方向(颠倒)
min.cutoff = min(pbmc$entropy), # 设置最小值
max.cutoff = max(pbmc$entropy), # 设置最大值
na.value = "lightgrey") + # 缺失值的颜色
theme(plot.title = element_text(hjust = 0.5, margin = margin(b = 15, t = 10)),
plot.margin = unit(c(0.8, 0.8, 0.8, 0.8), "cm"))
# 使用相等宽度组合图表
pdf("pbmc_uncertainty_metrics.pdf", width=18, height=7)
combined_plot <- cowplot::plot_grid(p1, p2, p3, ncol = 3, rel_widths = c(1.2, 1.2, 1.2))
print(combined_plot)
dev.off()
a,与 GPTCelltype 的比较,显示完全匹配和部分匹配(参见“方法”部分中的定义),准确性以百分比形式呈现。
b,发育中人类胸腺细胞图谱的性能比较。UMAP 可视化显示参考(第一),mLLMCelltype 预测(第二),GPTCelltype 预测(第三),以及群组级别 popV 预测(第四)的细胞类型注释,点按细胞类型着色。
c,肺细胞图谱(LCA)的性能比较。UMAP 可视化显示参考(第一),mLLMCelltype 预测(第二),GPTCelltype 预测(第三),以及群组级别 popV 预测(第四)的细胞类型注释,按细胞类型着色。
a, UMAP 可视化展示了 HNOCA 参考注释的主要神经细胞类型群体和发育状态。参考注释是通过使用 snapseed 工具生成的,该工具结合了层次细胞类型定义、标记基因评分和参考映射到人类发育大脑图谱中的过程。数据进一步通过 scPoli 集成和从参考大脑图谱中使用 scVI 和 scANVI 进行标签转移,特别是对于非端脑神经元和前体细胞。
b, UMAP 可视化展示了我们框架的注释,显示出在识别各种神经细胞类型和发育状态方面表现出强大的性能,当与大规模集成图谱中的参考注释进行评估时,具有很高的注释准确性。
c, UMAP 可视化展示了 GPTCelltype 的注释,其准确性低于我们框架,特别是在区分相关神经前体状态和专门的神经亚型方面。
a, UMAP 可视化图展示了参考注释中免疫细胞类型在整个生命周期中的分布。参考注释是通过对 220 名健康捐赠者的免疫细胞进行全面分析生成的,这些捐赠者覆盖了从出生到超过 90 岁的 13 个年龄组,结合了转录组数据和专家注释。
b, UMAP 可视化图展示了我们框架的注释,在与参考注释评估时显示出高注释准确性(76.6%),成功捕捉了复杂的发育过渡和多样的免疫细胞群体。
a,HLCA 参考注释的 UMAP 可视化,展示了主要细胞类型群体及其分布。HLCA 参考注释是通过一个分层框架生成的,包含 5 个粒度级别,从广泛的标签(第 1 级:免疫细胞、上皮细胞等)到精细的细胞类型(第 5 级:例如,初始 CD4 T 细胞)。数据整合和聚类是使用 scANVI 执行的,随后在不同分辨率下进行 Leiden 聚类(第 1 级:0.01,第 2 级:0.2,k = 30,第 3-5 级:0.2,k = 15/10)。最终的注释由六位肺脏生物学专家根据聚类结果、标记基因证据和 HLCA 核心聚类结果手动整理。
b,我们框架注释的 UMAP 可视化,与参考注释相比显示了高注释准确性。按照与参考相同的分层聚类方法,我们的框架逐级执行细胞类型注释。在每个级别,向 LLMs 提供全局标记基因(在一个簇中特异表达的基因,与所有其他簇相比)和姐妹标记基因(目标簇与同一父簇内的姐妹簇之间差异表达的基因),以及来自前一级别的父簇注释,以指导注释过程。
Yang, C., Zhang, X., & Chen, J. (2025). Large Language Model Consensus Substantially Improves the Cell Type Annotation Accuracy for scRNA-seq Data. bioRxiv. https://doi.org/10.1101/2025.04.10.647852