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

news2024/9/22 5:42:32

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

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

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

因此如何将大量的含有临床信息/表型的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.05
                     cutoff = 0.2, #the number of the Scissor selected cells should not exceed 20% of total cells in the single-cell data
                     family = "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) <- 0
    network[which(network != 0)] <- 1
    dataset0 <- 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.05
                     cutoff = 0.2, #the number of the Scissor selected cells should not exceed 20% of total cells in the single-cell data
                     family = "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.coloradmin.cn/o/1911236.html

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

相关文章

yolov8 人体姿态识别

引言 在计算机视觉的各种应用中&#xff0c;人体姿态检测是一项极具挑战性的任务&#xff0c;它能够帮助我们理解人体各部位的空间位置。本文将详细介绍如何使用 YOLOv8 和 Python 实现一个人体姿态检测系统&#xff0c;涵盖模型加载、图像预处理、姿态预测到结果可视化的全流…

探索 Qt 的 `QSqlDatabase`:数据库访问的桥梁

&#x1f60e; 作者介绍&#xff1a;欢迎来到我的主页&#x1f448;&#xff0c;我是程序员行者孙&#xff0c;一个热爱分享技术的制能工人。计算机本硕&#xff0c;人工制能研究生。公众号&#xff1a;AI Sun&#xff08;领取大厂面经等资料&#xff09;&#xff0c;欢迎加我的…

快速将一个网址打包成一个exe可执行文件

一、电脑需要node环境 如果没有下面有安装教程&#xff1a; node.js安装及环境配置超详细教程【Windows系统安装包方式】 https://blog.csdn.net/weixin_44893902/article/details/121788104 我的版本是v16.13.1 二、安装nativefier 这是一个GitHub上的开源项目&#xff1a…

自动驾驶算法———车道检测(一)

“ 在本章中&#xff0c;我将指导您构建一个简单但有效的车道检测管道&#xff0c;并将其应用于Carla 模拟器中捕获的图像。管道将图像作为输入&#xff0c;并产生车道边界的数学模型作为输出。图像由行车记录仪&#xff08;固定在车辆挡风玻璃后面的摄像头&#xff09;捕获。…

前端JS特效第26波:jQuery日期时间选择器插件

jQuery日期时间选择器插件&#xff0c;先来看看效果&#xff1a; 部分核心的代码如下&#xff1a; <!DOCTYPE html> <html> <head lang"zh-CN"> <meta charset"UTF-8"> <title>jQuery日期时间选择器插件 - PHP中文网</t…

学生管理系统 | python

1. 题目描述 ****************************** 欢迎使用学生管理系统 ****************************** 1. 添加学生 2. 查看学生列表 3. 查看学生信息 4. 删除学生 5. 退出系统 1 请输入学生姓名: zhangsan 请输入学生学号: 10010 请输入学生班级: 3 请输入学生成…

PolarisMesh源码系列——服务如何注册

前话 PolarisMesh&#xff08;北极星&#xff09;是腾讯开源的服务治理平台&#xff0c;致力于解决分布式和微服务架构中的服务管理、流量管理、配置管理、故障容错和可观测性问题&#xff0c;针对不同的技术栈和环境提供服务治理的标准方案和最佳实践。 PolarisMesh 官网&am…

前端面试题34(在移动应用中,通用的实时传输协议)

在移动应用中&#xff0c;选择实时传输协议时通常会考虑几个关键因素&#xff1a;网络效率、功耗、实时性、跨平台兼容性以及数据类型&#xff08;如文本、图像、视频&#xff09;。以下是几种常用的实时传输协议及其在移动应用中的适用性&#xff1a; 1. WebSocket WebSocke…

WIN32核心编程 - 动态链接库

公开视频 -> 链接点击跳转公开课程博客首页 -> 链接点击跳转博客主页 目录 动态链接库 创建动态链接库 相关函数 遍历模块 导出未文档化 动态链接库 动态链接库&#xff08;DLL&#xff09; 动态链接库&#xff08;Dynamic-Link Library&#xff0c;简称DLL&#x…

SpringBoot:SpringBoot中如何实现对Http接口进行监控

一、前言 Spring Boot Actuator是Spring Boot提供的一个模块&#xff0c;用于监控和管理Spring Boot应用程序的运行时信息。它提供了一组监控端点&#xff08;endpoints&#xff09;&#xff0c;用于获取应用程序的健康状态、性能指标、配置信息等&#xff0c;并支持通过 HTTP …

JWT(Json Web Token)在.NET Core中的使用

登录成功时生成JWT字符串目录 JWT是什么&#xff1f; JWT的优点&#xff1a; JWT在.NET Core 中的使用 JWT是什么&#xff1f; JWT把登录信息&#xff08;也称作令牌&#xff09;保存在客户端为了防止客户端的数据造假&#xff0c;保存在客户端的令牌经过了签名处理&#xf…

python3 ftplib乱码怎么解决

其实很简单。ftplib.FTP里面有个参数叫encoding。 如上图最后一行。所以在使用FTP时&#xff0c;主动指定编码格式即可。 ftp ftplib.FTP() ftp.encoding "utf-8" 再使用就可以了。

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

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

Kamailio-命令行指令kamctl与kamcmd

前文也有提到几种指令的用处&#xff0c;与web页面相比&#xff0c;它就是更原始、面向运维的&#xff0c;正常如果有管理页面也需要使用到&#xff1a; kamailio - SIP 服务器脚本kamdbctl - 创建和管理数据库的脚本&#xff0c;比如你使用MySQL作为其存储时就需要使用到这个…

看完这些内幕 你还会夹娃娃吗?

文&#xff5c;琥珀食酒社 作者 | 朱珀 听我一句劝 别再去抓娃娃了 因为你能抓多少 早已经被设计好了 只有娃娃机老板 才能爆赚80% 今天的这篇文章 来自粉丝阿凯的投稿 他不仅能让你创业避坑 还会告诉你 整个娃娃机行业的内幕 如此敢自揭行业内幕的老板 不是对这…

短视频矩阵搭建,用云微客获客更方便

你的同行都爆单了&#xff0c;你还在问什么是矩阵&#xff1f;让我来告诉你。短视频矩阵是短视频获客的一种全新玩法&#xff0c;是以品牌宣传、产品推广为核心的一个高端布局手段&#xff0c;也是非常省钱的一种方式。 1.0时代&#xff0c;一部手机一个账号&#xff1b;2.0时代…

Flutter Inno Setup 打包 Windows 程序

转载自&#xff1a;flutter桌面应用从开发配置到打包分发 - 掘金 (juejin.cn) 五.打包 1.创建 release 版本的应用 flutter build release 执行完成后&#xff0c; release包位置在项目的build->windows->runer文件夹中 2.应用程序分发 Windows 为 Windows 平台构建…

卷积神经网络之ResNet50迁移学习

数据准备 下载狗与狼分类数据集&#xff0c;数据来自ImageNet&#xff0c;每个分类有大约120张训练图像与30张验证图像。使用download接口下载数据集&#xff0c;并自动解压到当前目录。 全是小狗的图片 另一边全是狼的图片 加载数据集 狼狗数据集提取自ImageNet分类数据集&a…

迈巴赫S480升级原厂车载冰箱夏天是不是很有作用

迈巴赫 S480 升级原厂车载冰箱主要有以下作用&#xff1a; 1. 保鲜功能&#xff1a;可以在行车途中保持食物和饮料的新鲜度&#xff0c;特别是在长途旅行或炎热天气下&#xff0c;能让您随时享用清凉的饮品和新鲜的食物。 2. 提升舒适性&#xff1a;随时能够提供冷饮或冷藏的…

校园在校跑腿小程序源码系统 前后完全分离 带源代码包以及搭建教程

系统概述 随着移动互联网的飞速发展&#xff0c;校园生活也迎来了前所未有的便捷与高效。在校园内&#xff0c;学生们对于便捷服务的需求日益增长&#xff0c;从取快递、送餐到代买日常用品&#xff0c;各类跑腿服务逐渐成为校园生活的常态。为了满足这一市场需求&#xff0c;…