Scissor算法-从含有表型的bulkRNA数据中提取信息进而鉴别单细胞亚群

在做基础实验的时候,研究者都希望能够改变各种条件来进行对比分析,从而探索自己所感兴趣的方向。

在做数据分析的时候也是一样的,我们希望有一个数据集能够附加了很多临床信息/表型,然后二次分析者们就可以进一步挖掘。

然而现实情况总是数据集质量非常不错,但是附加的临床信息/表型却十分有限,这种状况在单细胞数据分析中更加常见。

因此如何将大量的含有临床信息/表型的bulk RNA测序数据和单细胞数据构成联系,这也是算法开发者们所重点关注的方向之一。

其中Scissor算法就可以从含有表型的bulk RNA数据中提取信息去鉴别单细胞亚群。

Scissor的分析原理主要是:

基于表达数据计算每个单细胞与bulk样本的相关性,筛选相关性较好的细胞群。

进一步结合表型信息,通过回归模型并加上惩罚项选出最相关的亚群。

原理详情可见:

1、github: https://github.com/sunduanchen/Scissor?tab=readme-ov-file

2、生信技能树教程1:https://mp.weixin.qq.com/s/jC6QTQCfcl_i4tTbFQAq7A

3、生信技能树教程2:https://mp.weixin.qq.com/s/dIYDNDPgIEDUkqqSr56GPg

分析步骤如下:

很多教程展示的是跟生存数据相关的分析,我这里采用二分类数据进行分析。

并且该算法最新一次更新是2021年,如果是使用seruat5版本构建单细胞数据集的话会报错,在进行分析前需要提取Scissor源代码修改一下。

1、导入数据和加载R包

rm(list = ls())
library(Scissor)
library(seurat)
scRNA <- readRDS("scRNA_tumor.rds") #这里采用了自己的处理的单细胞数据
load("step1output.Rdata") #这里也是自己处理的bulkRNA数据
sc_dataset <- scRNA
#dim(sc_dataset)
#[1] 20124  5042
bulk_dataset <- exp
#        GSM1310570 GSM1310571 GSM1310572 GSM1310573
#FAM174B      8.232      8.248      7.576      8.708
#AP3S2        5.998      6.079      5.695      6.653
#SV2B         6.107      6.630      5.686      7.886
#RBPMS2       6.718      7.630      7.410      5.762
phenotype <- pd
#                   title doubling time (days) survival time(months) gender doubling_group OS_group
#GSM1310570 Tumor T_A_001                  119                    52 female              1        0
#GSM1310571 Tumor T_B_003                   98                    44   male              0        0
#GSM1310572 Tumor T_C_005                   50                     3   male              0        0
#GSM1310573 Tumor T_D_007                   80                    28   male              0        1
#GSM1310574 Tumor T_E_009                  197                    47   male              1        0
#GSM1310575 Tumor T_F_011                  297                    52 female              1        0

我这里对OS和double时间进行了分组,变成了二分类数据。后面会单独提取。

2、先看一下处理好的分群结果

# Check
UMAP_celltype <- DimPlot(sc_dataset, reduction ="umap",group.by="celltype",label = T)
UMAP_celltype

3、运行Scissor,生存数据family设置"cox" ,logistic回归family设置"binomial"。

其中二分类变量在分析前需要设置tag

#提取想要的数据信息
colnames(phenotype)
phenotype <- phenotype[,"doubling_group"]
tag <- c("Quick","Slow")#分析时数据中不能存在na数据,去除或者改成0
#bulk_dataset <- na.omit(bulk_dataset)
bulk_dataset[is.na(bulk_dataset)] <- 0#正式开始分析
infos1 <- Scissor(bulk_dataset, sc_dataset, phenotype, tag = tag,alpha = 0.02, # 默认0.05cutoff = 0.2, #the number of the Scissor selected cells should not exceed 20% of total cells in the single-cell datafamily = "binomial", Save_file = './result.RData')
# Error in as.matrix(sc_dataset@assays$RNA@data) : 
# no slot of name "data" for this object of class "Assay5"

Error in as.matrix(sc_dataset@assays$RNA@data) : no slot of name "data" for this object of class "Assay5"

看来这个算法暂不直接适用于seraut5版本,没办法只能提取原代码进行稍作修改,把读取单细胞数据data部分的代码内容增加layer即可,新的代码保存之后再调用。

4、修改之后的代码,命名为RUNscissor

其实就是修改了里边的读取方式:sc_exprs <- as.matrix(sc_dataset@assaysdata)

RUNScissor <- function (bulk_dataset, sc_dataset, phenotype, tag = NULL, alpha = NULL, cutoff = 0.2, family = c("gaussian", "binomial", "cox"), Save_file = "Scissor_inputs.RData", Load_file = NULL) 
{library(Seurat)library(Matrix)library(preprocessCore)# 确保 phenotype 是向量phenotype <- as.numeric(phenotype)if (is.null(Load_file)) {common <- intersect(rownames(bulk_dataset), rownames(sc_dataset))if (length(common) == 0) {stop("There is no common genes between the given single-cell and bulk samples.")}if (class(sc_dataset) == "Seurat") {sc_exprs <- as.matrix(sc_dataset@assays$RNA@layers$data)rownames(sc_exprs) <- rownames(sc_dataset)colnames(sc_exprs) <- colnames(sc_dataset)network <- as.matrix(sc_dataset@graphs$RNA_snn)} else {sc_exprs <- as.matrix(sc_dataset)Seurat_tmp <- CreateSeuratObject(sc_dataset)Seurat_tmp <- FindVariableFeatures(Seurat_tmp, selection.method = "vst", verbose = FALSE)Seurat_tmp <- ScaleData(Seurat_tmp, verbose = FALSE)Seurat_tmp <- RunPCA(Seurat_tmp, features = VariableFeatures(Seurat_tmp), verbose = FALSE)Seurat_tmp <- FindNeighbors(Seurat_tmp, dims = 1:10, verbose = FALSE)network <- as.matrix(Seurat_tmp@graphs$RNA_snn)}diag(network) <- 0network[which(network != 0)] <- 1dataset0 <- cbind(bulk_dataset[common, ], sc_exprs[common, ])dataset0 <- as.matrix(dataset0)dataset1 <- normalize.quantiles(dataset0)rownames(dataset1) <- rownames(dataset0)colnames(dataset1) <- colnames(dataset0)Expression_bulk <- dataset1[, 1:ncol(bulk_dataset)]Expression_cell <- dataset1[, (ncol(bulk_dataset) + 1):ncol(dataset1)]X <- cor(Expression_bulk, Expression_cell)quality_check <- quantile(X)print("|**************************************************|")print("Performing quality-check for the correlations")print("The five-number summary of correlations:")print(quality_check)print("|**************************************************|")if (quality_check[3] < 0.01) {warning("The median correlation between the single-cell and bulk samples is relatively low.")}if (family == "binomial") {Y <- as.numeric(phenotype)z <- table(Y)if (length(z) != length(tag)) {stop("The length differs between tags and phenotypes. Please check Scissor inputs and selected regression type.")} else {print(sprintf("Current phenotype contains %d %s and %d %s samples.", z[1], tag[1], z[2], tag[2]))print("Perform logistic regression on the given phenotypes:")}}if (family == "gaussian") {Y <- as.numeric(phenotype)z <- table(Y)if (length(z) != length(tag)) {stop("The length differs between tags and phenotypes. Please check Scissor inputs and selected regression type.")} else {tmp <- paste(z, tag)print(paste0("Current phenotype contains ", paste(tmp[1:(length(z) - 1)], collapse = ", "), ", and ", tmp[length(z)], " samples."))print("Perform linear regression on the given phenotypes:")}}if (family == "cox") {Y <- as.matrix(phenotype)if (ncol(Y) != 2) {stop("The size of survival data is wrong. Please check Scissor inputs and selected regression type.")} else {print("Perform cox regression on the given clinical outcomes:")}}save(X, Y, network, Expression_bulk, Expression_cell, file = Save_file)} else {load(Load_file)}if (is.null(alpha)) {alpha <- c(0.005, 0.01, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9)}for (i in 1:length(alpha)) {set.seed(123)fit0 <- APML1(X, Y, family = family, penalty = "Net", alpha = alpha[i], Omega = network, nlambda = 100, nfolds = min(10, nrow(X)))fit1 <- APML1(X, Y, family = family, penalty = "Net", alpha = alpha[i], Omega = network, lambda = fit0$lambda.min)if (family == "binomial") {Coefs <- as.numeric(fit1$Beta[2:(ncol(X) + 1)])} else {Coefs <- as.numeric(fit1$Beta)}Cell1 <- colnames(X)[which(Coefs > 0)]Cell2 <- colnames(X)[which(Coefs < 0)]percentage <- (length(Cell1) + length(Cell2)) / ncol(X)print(sprintf("alpha = %s", alpha[i]))print(sprintf("Scissor identified %d Scissor+ cells and %d Scissor- cells.", length(Cell1), length(Cell2)))print(sprintf("The percentage of selected cell is: %s%%", formatC(percentage * 100, format = "f", digits = 3)))if (percentage < cutoff) {break}cat("\n")}print("|**************************************************|")return(list(para = list(alpha = alpha[i], lambda = fit0$lambda.min, family = family), Coefs = Coefs, Scissor_pos = Cell1, Scissor_neg = Cell2))
}

5、运行RUNScissor

source("~/Desktop/practice/5-Scissor/RUNScissor.R")
infos1 <- RUNScissor(bulk_dataset, sc_dataset, phenotype, tag = tag,alpha = 0.02, # 默认0.05cutoff = 0.2, #the number of the Scissor selected cells should not exceed 20% of total cells in the single-cell datafamily = "binomial", Save_file = './doubling_time.RData')#[1] "|**************************************************|"
#[1] "Performing quality-check for the correlations"
#[1] "The five-number summary of correlations:"
#        0%        25%        50%        75%       100% 
#0.03017724 0.29070054 0.32966267 0.37428284 0.70446959 
#[1] "|**************************************************|"
#[1] "Current phenotype contains 38 Quick and 43 Slow samples."
#[1] "Perform logistic regression on the given phenotypes:"
#[1] "alpha = 0.02"
#[1] "Scissor identified 202 Scissor+ cells and 690 Scissor- cells."
#[1] "The percentage of selected cell is: 17.691%"
#[1] "|**************************************************|"

Scissor算法首先给出不同比例细胞下单细胞和bulkRNA数据之间的相关性值,如果相关性过低(< 0.01),则会给出warning信息。

此外,表型分组分别为 38例Quick 样本和 43 例Slow样本,数据采用了logistic回归分析,alpha设置为0.02,共获得了202 Scissor+ 细胞和690 Scissor- 细胞。这里的Scissor+ 细胞是指Slow组样本,一般默认表型信息设置为0和1,0代表未发生感兴趣事件,1代表发生了感兴趣事件,在设置tag信息时需要跟表型信息顺序对应起来。

值得重点关注的是这里的alpha和cutoff值。cutoff值则代表所选择细胞的百分比,默认是小于0.2(20%)。Alpha值平衡了 L1范数和网络惩罚的影响,Alpha值越大则惩罚力度也越大从而得到的scissor+/-细胞数也就越少。通常我们应当保证不超过cutoff的范围下,去自定义alpha值。

6、可视化

Scissor_select <- rep(0, ncol(sc_dataset))
names(Scissor_select) <- colnames(sc_dataset)
Scissor_select[infos1$Scissor_pos] <- "Scissor+"
Scissor_select[infos1$Scissor_neg] <- "Scissor-"
sc_dataset <- AddMetaData(sc_dataset, metadata = Scissor_select, col.name = "scissor")
UMAP_scissor <- DimPlot(sc_dataset, reduction = 'umap', group.by = 'scissor',cols = c('grey','royalblue','indianred1'), pt.size = 0.001, order = c("Scissor+","Scissor-"))
UMAP_scissor
table(sc_dataset$scissor)
patchwork::wrap_plots(plots = list(UMAP_celltype,UMAP_scissor), ncol = 2)
saveRDS(sc_dataset,"sc_dataset.rds")

然后可以对两张图片进行对比。

致谢:感谢曾老师,小洁老师以及生信技能树团队全体成员。

:若对内容有疑惑或者有发现明确错误的朋友,请联系后台(希望多多交流)。更多内容可关注公众号:生信方舟

- END -

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/43684.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

共生与变革:AI在开发者世界的角色深度剖析

在科技日新月异的今天&#xff0c;人工智能&#xff08;AI&#xff09;已不再是遥不可及的概念&#xff0c;而是逐步渗透到我们工作与生活的每一个角落。对于开发者这一群体而言&#xff0c;AI的崛起既带来了前所未有的机遇&#xff0c;也引发了关于其角色定位的深刻讨论——AI…

【分布式系统】ceph部署(命令+截图巨详细版)

目录 一.存储概述 1.单机存储设备 2.单机存储的问题 3.商业存储 4.分布式存储​编辑 4.1.什么是分布式存储 4.2.分布式存储的类型 二.ceph概述 1.ceph优点 2.ceph架构 3.ceph核心组件 4.OSD存储后端 5.ceph数据存储过程 6.ceph版本发行生命周期 7.ceph集群部署 …

二叉树超详细解析

二叉树 目录 二叉树一级目录二级目录三级目录 1.树的介绍1.1树的定义1.2树的基本术语1.3相关性质 2.二叉树介绍2.1定义2.2 性质 3.二叉树的种类3.1 满二叉树3.2完全二叉树3.3 二叉查找树特点&#xff1a;二叉查找树的节点包含的基本信息&#xff1a; 3.4 平衡二叉树 4.二叉树的…

研华运动控制卡在LabVIEW中的应用

在现代工业和科研领域中&#xff0c;精密运动控制系统的需求日益增加。这些系统广泛应用于自动化生产线、精密机械加工、机器人控制、光学仪器调试和实验室自动化设备等诸多领域。本文以研华公司的运动控制卡为例&#xff0c;详细介绍其在LabVIEW中的应用&#xff0c;展示如何通…

初识数组(二)

目录 1. 二维数组的初始化 1&#xff09; 不完全初始化 2&#xff09; 完全初始化 3&#xff09; 按照行初始化 4&#xff09; 初始化时省略行&#xff0c;但是不能省略列 2.二维数组的使用 1&#xff09; 二维数组的下标 2&#xff09;二维数组的输入和输出 3. 二维数…

gif压缩大小但不改变画质的最佳方法,7个gif压缩免费工具别错过!

你会不会也碰到过当你需要在自媒体平台上上传gif文件时&#xff0c;你会发现网页端最大限制为15MB&#xff0c;而手机端最大限制为5MB。那么如何在不不改变画质的同时压缩gif大小呢&#xff1f;如今&#xff0c;由于其特殊的动画以及快速传输的特点&#xff0c;gif文件已经成为…

基于Hadoop平台的电信客服数据的处理与分析③项目开发:搭建基于Hadoop的全分布式集群---任务8:测试Hadoop集群的可用性

任务描述 测试Hadoop集群的可用性 任务指导 1. 在Web UI查看HDFS和YARN状态 2. 测试HDFS和YARN的可用性 任务实现 1. 在Web UI查看HDFS和YARN状态 在【master1】打开Web浏览器访问Hadoop其中HDFS NameNode对应的Web UI地址如下&#xff1a; http://master1:50070 如下…

【动态规划Ⅵ】背包问题 /// 组合问题

背包问题 什么是背包问题0-1背包问题分数背包完全背包问题重复背包问题 背包问题例题416. 分割等和子集474. 一和零 完全平方数279. 完全平方数322. 零钱兑换 排列与组合组合&#xff0c;无重复&#xff1a;518. 零钱兑换 II排列&#xff0c;可重复&#xff1a;377. 组合总和 Ⅳ…

虚拟内存【Linux】

虚拟内存 为什么需要虚拟内存Linux虚拟内存的结构32位系统下的虚拟地址空间64位系统下的虚拟地址空间页表多级页表TLB 流程虚拟内存的作用 为什么需要虚拟内存 为了在进行多进程编码进行内存访问的时候保持内存的隔离性&#xff0c;数据安全性&#xff0c;所以出现了虚拟内存。…

Spring Cloud 引入

1.单体架构&#xff1a; 定义&#xff1a;所有的功能实现都打包成一个项目 带来的后果&#xff1a; ①后端服务器的压力越来越大&#xff0c;负载越来越高&#xff0c;甚至出现无法访问的情况 ②业务越来越复杂&#xff0c;为了满足用户的需求&#xff0c;单体应用也会越来越…

入门PHP就来我这(高级)19 ~ 捕获sql错误

有胆量你就来跟着路老师卷起来&#xff01; -- 纯干货&#xff0c;技术知识分享 路老师给大家分享PHP语言的知识了&#xff0c;旨在想让大家入门PHP&#xff0c;并深入了解PHP语言。 接着上篇我们来看下sql错误的捕获模式。 1 PDO中捕获SQL语句中的错误 在PDO中有3种方法可以捕…

大话光学原理:1.“实体泛光说”、反射与折射

一、实体泛光说 在古希腊&#xff0c;那些喜好沉思的智者们中&#xff0c;曾流传着一个奇妙的设想&#xff1a;他们认为&#xff0c;我们的眼睛仿佛伸出无数触手般的光线&#xff0c;这些光线能向四面八方延伸&#xff0c;紧紧抓住周围的每一个物体。于是&#xff0c;当我们凝视…

生成多个ssh访问不同git

如果&#xff0c;你的git代码仓库&#xff0c;比如说腾讯云coding&#xff0c;通过ssh秘钥访问&#xff0c;一直用的好好的&#xff0c;有一天&#xff0c;你又增加一个aliyun云效的代码仓库&#xff0c;又配置了aliyun云效的秘钥并且&#xff0c;根据aliyun云效的官方文档上传…

Angular进阶之九: JS code coverage是如何运作的

环境准备 需要用到的包 node 18.16.0# Javascript 代码编辑"babel/core": "^7.24.7","babel/preset-env": "^7.24.7","babel-loader": "^9.1.3",# 打包时使用的 module&#xff0c; 给代码中注入新的方法# http…

群晖NAS配置WebDav服务结合内网穿透实现跨平台云同步思源笔记

文章目录 前言1. 开启群晖WebDav 服务2. 本地局域网IP同步测试3. 群晖安装Cpolar4. 配置远程同步地址5. 笔记远程同步测试6. 固定公网地址7. 配置固定远程同步地址 前言 本教程主要分享如何将思源笔记、cpolar内网穿透和群晖WebDav三者相结合&#xff0c;实现思源笔记的云同步…

打开excel时弹出stdole32.tlb

问题描述 打开excel时弹出stdole32.tlb 如下图&#xff1a; 解决方法 打开 Microsoft Excel 并收到关于 stdole32.tlb 的错误提示时&#xff0c;通常意味着与 Excel 相关的某个组件或类型库可能已损坏或不兼容。 stdole32.tlb 是一个用于存储自动化对象定义的类型库&#x…

vue 切换主题色切换主题色切换主题色切换主题色切换主题色

第一种&#xff1a;使用CSS变量 CSS变量&#xff08;Custom Properties&#xff09;是CSS的一种新特性 1.实现需求&#xff1a;自定义颜色 定义变量 全局的theme.css :root {--primary-color:red; }在组件中使用这些变量 demo.vue <template><div class"main…

海外多语言盲盒APP系统开发

随着盲盒的全球化发展&#xff0c;盲盒已经成为了一个热门行业&#xff0c;不仅深受我国消费者的青睐&#xff0c;更是深受海外消费者的喜爱。目前&#xff0c;盲盒出海已经成为了企业拓展市场的新机会。 在数字化时代&#xff0c;海外盲盒APP为企业提供了一个快速打开海外盲盒…

应急响应——勒索病毒

先上搜索引擎上搜 也可以用360来杀 但是都无法解密 可以解密的&#xff1a; linux

【嵌入式DIY实例-ESP8266篇】-LCD ST7735显示BME280传感器数据

LCD ST7735显示BME280传感器数据 文章目录 LCD ST7735显示BME280传感器数据1、硬件准备与接线2、代码实现本文中将介绍如何使用 ESP8266 NodeMCU 板(ESP12-E 模块)和 BME280 气压、温度和湿度传感器构建气象站。 NodeMCU 微控制器 (ESP8266EX) 从 BME280 传感器读取温度、湿度…