使用非负最小二乘回(NNLS)归进行细胞类型转移

2019年发表在Nature上的文章【The single-cell transcriptional landscape of mammalian organogenesis】在方法部分提到,使用NNLS(non-negative linear-square)回归的方法分析两个细胞图谱数据集中相关细胞类型。

这个方法,在我搜索的中文教程中都没有出现过,所以这里以两个pbmc的数据集为例进行介绍,如何复现文章的方法。

10x的细胞数据集的预处理部分不做过多介绍, 如下代码以10x官网提供的数据为例

library(Seurat)
pbmc.data <- Read10X_h5("./data/10x/10k_PBMC_3p_nextgem_Chromium_X_filtered_feature_bc_matrix.h5")
seu.obj <- CreateSeuratObject(counts = pbmc.data, 
                              project = "pbmc10k", 
                              min.cells = 3, 
                              min.features = 200)
library(dplyr)
seu.obj <- seu.obj  %>%
  Seurat::NormalizeData(verbose = FALSE) %>%  #归一化
  FindVariableFeatures(selection.method = "vst") %>%  #筛选特征,找高变基因
  ScaleData(verbose = FALSE) %>%  #标准化
  RunPCA(pc.genes = seu.obj@var.genes, npcs = 100, verbose = FALSE)  %>% #降维,降噪
  FindNeighbors( dims = 1:10) %>% #建立SNN
  FindClusters( resolution = 0.5) %>% #分群
  RunUMAP( dims = 1:10) # 非线性降维

相同的处理流程我们应用到Seurat 3k教程里. 最终我们得到两个Seurat对象

  • seu.obj1: 10x的10k pmbc
  • seu.obj2: 10x的3k pbmc

结果对比

基本上看多了PBMC数据的UMAP结果,大概就能通过UMAP的拓扑结构推断不同的细胞类型,比如说两个数据集的cluster3, 肯定都是B细胞了。

接着,我们基于文章的描述来实现代码

第一步是对数据按照cluster进行合并,并进行标准化

To identify correlated cell types between two cell atlas datasets, we first aggregated the cell-type-specific UMI counts, normalized by the total count, multiplied by 100,000 and log-transformed after adding a pseudocount

# 确保两个数据集的特征数相等
shared_gene <- intersect(rownames(seu.obj), row.names(seu.obj2))

## 计算各个cluster之和并标准化
seu.obj.mat <- Seurat::AggregateExpression(seu.obj, assays = "RNA",  features = shared_gene,slot = "count")$RNA
seu.obj.mat <- seu.obj.mat / rep(colSums(seu.obj.mat), each = nrow(seu.obj.mat))
seu.obj.mat <- log10(seu.obj.mat * 100000 + 1)


seu.obj.mat2 <- Seurat::AggregateExpression(seu.obj2, assays = "RNA", features = shared_gene, slot = "count")$RNA
seu.obj.mat2 <- seu.obj.mat2 / rep(colSums(seu.obj.mat2), each = nrow(seu.obj.mat2))
seu.obj.mat2 <- log10(seu.obj.mat2 * 100000 + 1)

第二步是筛选基因. 文章为了提高准确性,先根据目标数据集中给定细胞类型和整体细胞类型中位数的倍数变化,选择前200个;然后给根据目标数据集中给定细胞类型和其他细胞类型最大值的倍数变化,选择前200个,对两个结果进行合并。(我使用差异富集的marker的前100个,发现效果也差不多)

To improve accuracy and specificity, we selected cell-type-specific genes for each target cell type by (1) ranking genes on the basis of the expression fold-change between the target cell type versus the median expression across all cell types, and then selecting the top 200 genes; (2) ranking genes on the basis of the expression fold-change between the target cell type versus the cell type with maximum expression among all other cell types, and then selecting the top 200 genes; and (3) merging the gene lists from steps (1) and (2).

# 以cluster3为例
cluster <- 3

seu.obj.gene <- seu.obj.mat[, cluster + 1]

gene_fc <- seu.obj.gene / apply(seu.obj.mat, 1, median)
gene_list1 <- names(sort(gene_fc, decreasing = TRUE)[1:200])

gene_fc <- seu.obj.gene / apply(seu.obj.mat[,-(cluster+1)], 1, max)
gene_list2 <- names(sort(gene_fc, decreasing = TRUE)[1:200])

gene_list <- unique(c(gene_list1, gene_list2))

第三步: 是在相关系数不为负的限制下,求解 T a = β 0 a + β 1 a M b T_a = \beta_0a + \beta_{1a}M_b Ta=β0a+β1aMb. 其中 M b M_b Mb 是预测数据集的基因表达量, β 1 a \beta_{1a} β1a就是对应系数。

Ta <- seu.obj.mat[gene_list, cluster+1]

Mb <- seu.obj.mat2[gene_list,]

library(lsei)
solv <- nnls(Mb, Ta)
corr <- solv$x

这里算出预测数据集的cluster3系数最高,为0.93, 其他都是0.

第四步: 调换预测数据集和目标数据集,重新进行第二步和第三步

Similarly, we then switch the order of datasets A and B, and predict the gene expression of target cell type (Tb) in dataset B with the gene expression of all cell types (Ma) in dataset A.

#  predict a with b
seu.obj.gene <- seu.obj.mat2[, cluster]

gene_fc <- seu.obj.gene / apply(seu.obj.mat2, 1, median)
gene_list1 <- names(sort(gene_fc, decreasing = TRUE)[1:200])

gene_fc <- seu.obj.gene / apply(seu.obj.mat2[,-cluster], 1, max)
gene_list2 <- names(sort(gene_fc, decreasing = TRUE)[1:200])

gene_list <- unique(c(gene_list1, gene_list2))

Ta <- seu.obj.mat2[gene_list, cluster]
Mb <- seu.obj.mat[gene_list,]
solv <- nnls(Mb, Ta)
corr2 <- solv$x

第五步: 经过上面运算后,我们就得到对于数据集A中的各个细胞类型,数据集B各个细胞类型对应的回归系数,记作 β a b \beta_{ab} βab 以及对于数据集B中的各个细胞类型,数据集A各个细胞类型对应的回归系数, β b a \beta_{ba} βba, 通过如下公式整合两个参数, β = 2 ( β a b + 0.01 ) ( β b a + 0.01 ) \beta = 2(\beta_{ab} + 0.01)(\beta_{ba} + 0.01) β=2(βab+0.01)(βba+0.01)

# 批量计算各个类群的回归系数
list1 <- list()
for (cluster in seq(1, ncol(seu.obj.mat))) {
  
  #  predict a with b
  seu.obj.gene <- seu.obj.mat[, cluster]
  
  gene_fc <- seu.obj.gene / apply(seu.obj.mat, 1, median)
  gene_list1 <- names(sort(gene_fc, decreasing = TRUE)[1:200])
  
  gene_fc <- seu.obj.gene / apply(seu.obj.mat[,-cluster], 1, max)
  gene_list2 <- names(sort(gene_fc, decreasing = TRUE)[1:200])
  
  gene_list <- unique(c(gene_list1, gene_list2))
  
  Ta <- seu.obj.mat[gene_list, cluster]
  Mb <- seu.obj.mat2[gene_list,]
  solv <- nnls(Mb, Ta)
  corr <- solv$x
  
  list1[[cluster]] <- corr
  
}
list2 <- list()
for (cluster in seq(1, ncol(seu.obj.mat2))) {
  
  #  predict a with b
  seu.obj.gene <- seu.obj.mat2[, cluster]
  
  gene_fc <- seu.obj.gene / apply(seu.obj.mat2, 1, median)
  gene_list1 <- names(sort(gene_fc, decreasing = TRUE)[1:200])
  
  gene_fc <- seu.obj.gene / apply(seu.obj.mat2[,-cluster], 1, max)
  gene_list2 <- names(sort(gene_fc, decreasing = TRUE)[1:200])
  
  gene_list <- unique(c(gene_list1, gene_list2))
  
  Ta <- seu.obj.mat2[gene_list, cluster]
  Mb <- seu.obj.mat[gene_list,]
  solv <- nnls(Mb, Ta)
  corr <- solv$x
  
  list2[[cluster]] <- corr
  
}

# 合并结果
mat1 <- do.call(rbind, list1)
mat2 <- do.call(rbind, list2)

# 计算系数
beta <- 2*(mat1 + 0.01) *  t(mat2+0.01)

row.names(beta) <- paste0("C", 1:nrow(beta)-1)

colnames(beta) <- paste0("C", 1:ncol(beta)-1)
# 可视化
pheatmap::pheatmap(beta, cluster_rows = FALSE,cluster_cols = FALSE)

结果如下:

image.png

观察发现: 3k数据集UMAP上邻居的C4,6对应10k数据集的C6和C8也是临近关系, 说明基于NNLS的预测方法,也是相对比较准确。

当然文章也通过对多个数据集的相互比较验证了这个分析方法。

For validation, we first applied cell-type correlation analysis to independently generated and annotated analyses of the adult mouse kidney (sci-RNA-seq component of sci-CAR19 versus Microwell-seq). We subsequently compared cell subclusters from this study (with detected doublet-cell ratio ≤10%) to fetus-related cell types (those with annotations including the term ‘fetus’) from the Microwell-seq-based MCA. A similar comparison was performed against cell types annotated in BCA.

但是,文章并没有解释他可以用NNLS回归的方法做标记的迁移,鉴于他没有引述参考文章,我们可以认为这是作者第一次提出的标记迁移思路。所以,不妨让我做一些推测吧。

我们比较耳熟能详的分析是,线性回归里面的最小二乘法,也就是给定两组变量a和b, 通过最小二乘的方法求解a = bx + c中的系数x和c. 那么,假设存在三个细胞类型A, B,C. 其中A和B是同一类型,A和C不是同一类型。对于同一种细胞类型的两个数据,只不过由于实验,测序和分析等各种因素,导致基因表达值并不相同,但是存在着一定关联。我们可以通过求解 A = Bx + Cy 中的系数x, y,通过比较系数来评估A和哪个细胞类型最类似。进一步, 显然我们不能让一个细胞类型的贡献为负,最少是无作用,也就是0, 因此我们就得 限定系数不为负,也就是非负最小二乘(non-negative linear square, NNLS)回归。

### 答1: 非负最小二乘(Non-negative least squares)是一种用于解决非负线性归问题的方法。在R语言中,可以使用nnls函数进行非负最小二乘归。 该函数的使用方法如下: nnls(X, y) 其中,X表示自变量矩阵,y表示因变量向量。X可以是一个多维矩阵,y是一个一维向量。函数返一个列表,包含两个元素:coefficients和residuals。 coefficients是一个向量,表示模型的归系数。每个系数都对应着自变量矩阵X的每一列。 residuals是一个向量,表示残差。它是实际因变量y与基于模型预测的因变量y之间的差异。 在使用nnls函数进行非负最小二乘归时,我们需要注意以下几点: 首先,输入的自变量矩阵X和因变量向量y的维度需要匹配。X的列数应该等于y的长度。 其次,在实际应用中,我们通常需要根据数据的特点来选择合适的自变量矩阵X和因变量向量y。 最后,由于非负最小二乘归是一个非凸优化问题,因此在某些情况下可能会有多个局部最小值。为了获得更稳定和可靠的结果,可以尝试多次运行nnls函数,并选择具有最小残差的模型作为最终结果。 总之,nnls函数是R语言中用于进行非负最小二乘归的方法。通过输入自变量矩阵X和因变量向量y,可以得到模型的归系数和残差。使用此函数能够帮助我们解决非负线性归问题,并获得准确的模型结果。 ### 答2: 非负最小二乘(Non-negative Least Squares, 简称NNLS)是一种归分析方法,适用于目标函数有非负限制的情况。而R语言中的nnls函数可以用于实现非负最小二乘的计算。 nnls函数的语法为:nnls(A, b),其中A是一个矩阵,b是一个向量。该函数将根据输入的A和b,通过非负最小二乘算法来估计线性模型的参数。 具体使用时,首先需要将问题转化为线性模型的形式。假设有一个线性模型为y = Ax + ε,其中y是一个观测值向量,A是一个已知的设计矩阵,x是待估计的参数向量,ε是观测误差。我们的目标是通过最小化误差平方和来估计参数x。 为了实现非负约束,nnls函数会对估计的参数x进行调整,使其保持非负。这样做的好处是可以获得更加准确的估计结果,并且可以满足实际问题中的非负限制。 通过调用nnls函数,输入A和b,即可得到非负最小二乘的估计结果。函数返一个列表对象,其中包含非负最小二乘的估计参数和相应的拟合值。 需要注意的是,nnls函数在R语言中属于非财统计模型包中。在使用之前,需要先加载相应的包,可以通过library(NNLS)来加载。 总之,非负最小二乘是一种处理非负约束的归分析方法,而R语言中的nnls函数可以实现这一方法。使用nnls函数,可以实现非负最小二乘的计算,并对线性模型的参数进行估计。 ### 答3: 非负最小二乘(Non-negative least squares)是一种用于求解最小二乘问题的算法,其在R语言中被实现为nnls函数。 在统计学和数值分析领域中,最小二乘法是一种常见的数据拟合方法,用于找到一个数学模型与一组数据的观测值之间的最佳匹配。然而,有时我们希望限制模型的参数为非负值,以便更好地解释和应用结果。 nnls函数在R语言中提供了一种实现非负最小二乘法的途径。它的输入是一个矩阵X和一个向量y,其中X代表自变量的特征矩阵,y代表因变量的观测向量。函数的目标是最小化残差平方和,即min ||y - Xβ||^2,同时满足β >= 0,其中β是一个长度与自变量特征数目相等的向量。 nnls函数使用了基于法的迭代算法,通过不断更新参数向量β来逼近最优解。该算法在每一步都通过调整β中的一个参数来最小化残差平方和,并且将其限制在非负值范围内。最终,函数返最优参数向量β和残差平方和的值。 使用nnls函数的一个常见的应用是在图像处理中,用于解决非负矩阵分解(Non-negative Matrix Factorization,NMF)问题。NMF是一种常见的降维方法,通过将一个非负矩阵分解为两个非负矩阵的乘积来提取数据的潜在结构。nnls函数在NMF中用于更新关于数据的低秩分解,从而获得更好的重建结果。 总之,非负最小二乘法是一种实现最小二乘问题的算法,可以在R语言中通过nnls函数来进行计算。其应用领域包括数据拟合、图像处理等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值