前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关键单细胞亚群辅助判定之生存分析

关键单细胞亚群辅助判定之生存分析

作者头像
生信技能树
发布2023-10-30 16:30:29
9930
发布2023-10-30 16:30:29
举报
文章被收录于专栏:生信技能树

做过单细胞转录组数据分析的小伙伴都知道,多分组多样品的单细胞项目很容易就十几万个单细胞了所以第一层次降维聚类分群就有十个左右亚群,然后每个亚群又可以细分十几个,算起来就是近百的单细胞亚群。

这样的话图表会非常多,但是数据分析的终极目标是发文章,而文章就必须要有故事性有落脚点。接下来我们就系统性梳理一下使用生存分析来辅助判定关键单细胞亚群。这里我们采用的仍然是2022的肺腺癌相关的文章,标题是:《Delineating the dynamic evolution from preneoplasia to invasive lung adenocarcinoma by integrating single-cell RNA sequencing and spatial transcriptomics》,肺癌单细胞数据集也有好几十个了,拿到表达量矩阵后的第一层次降维聚类分群通常是:

  • immune (CD45+,PTPRC),
  • epithelial/cancer (EpCAM+,EPCAM),
  • stromal (CD10+,MME,fibo or CD31+,PECAM1,endo)

参考我前面介绍过 CNS图表复现08—肿瘤单细胞数据第一次分群通用规则,这3大单细胞亚群构成了肿瘤免疫微环境的复杂。其实这个文章的第一层次降维聚类分群详见:换一个分析策略会导致文章的全部论点都得推倒重来吗,然后文章针对上皮细胞进行细分后,使用inferCNV判断了恶性的亚群,接下来就使用生存分析从恶性亚群里面的挑选了增殖亚群(UBE2C+),因为它这个亚群的基因可以在tcga数据库的luad数据集里面的有统计学显著的生存分析意义。如下所示:

增殖亚群(UBE2C+)

生存分析三步走

生存分析主要是需要一个病人队列而且病人的生存时间信息以及其最后的状态信息是齐全的,然后我们需要病人的表达量矩阵信息,这样的话就可以从矩阵里面挑选感兴趣的基因或者说基因列表去矩阵里面打分后,把病人高低分组后做生存分析来判断其重要性。

这里我们采用ucsc的xena浏览器下载tcga数据库的luad数据集表达量矩阵,每个癌症都有固定的数据文件格式:

比如TCGA-LAML,如下所示:

代码语言:javascript
复制
https://gdc-hub.s3.us-east-1.amazonaws.com/download/TCGA-LAML.htseq_counts.tsv.gz
https://gdc-hub.s3.us-east-1.amazonaws.com/download/TCGA-LAML.GDC_phenotype.tsv.gz
https://gdc-hub.s3.us-east-1.amazonaws.com/download/TCGA-LAML.survival.tsv
https://gdc-hub.s3.us-east-1.amazonaws.com/download/TCGA-LAML.mutect2_snv.tsv.gz

很容易批量下载,也很容易根据感兴趣的癌症来下载对应的文件。

第1步:格式化表达量矩阵文件

下面的代码很容易理解,需要自己熟悉这个TCGA-LUAD.htseq_counts.tsv.gz文件的规则即可:

代码语言:javascript
复制
rm(list=ls())

library(data.table) 
dat <- data.table::fread('TCGA-LUAD.htseq_counts.tsv.gz',
                          data.table = F)  
head(dat[,1:4])
tail(dat[,1:4]) 
dat = dat[1:(nrow(dat)-5),]
rownames(dat) = dat$Ensembl_ID
a = dat
a = a[,-1]
##逆转 log
a = as.matrix(2^a - 1)
# 用apply转换为整数矩阵
head(a[,1:4])
tail(a[,1:4]) 
colSums(a)/1e6
# 普通转录组定量 20m
# 想看融合基因,可变剪切,100M
exp = apply(a, 2, as.integer)
rownames(exp) = rownames(dat)
exp= log(edgeR::cpm(exp)+1)
library(stringr)
head(rownames(exp))
library(AnnoProbe)
library(tinyarray)
rownames(exp) = substr(rownames(exp), 1, 15) 
re = annoGene(rownames(exp),ID_type = "ENSEMBL");head(re)
exp = trans_array(exp,ids = re,from = "ENSEMBL",to = "SYMBOL")
head(exp[,1:4])
tail(exp[,1:4]) 
proj='tcga-luad'
save(exp,file = paste0(proj,".htseq_counts.rdata") ) 

第2步:整理临床信息

做生存分析的时候,其实只需要表达量矩阵里面的肿瘤样品即可,所以简单的过滤一下。然后临床信息里面我们也是简单的取 OS 即可:

代码语言:javascript
复制
rm(list=ls())

proj='tcga-luad'
load(file = paste0(proj,".htseq_counts.rdata") )
Group = ifelse(as.numeric(str_sub(colnames(exp),14,15)) < 10,'tumor','normal')  
Group = factor(Group,levels = c("normal","tumor"))
print(table(Group))
# 生存分析只需要tumor样品即可
exprSet = exp[,Group=='tumor']


clinical = read.delim('TCGA-LUAD.GDC_phenotype.tsv.gz',
                      fill = T,header = T,sep = "\t")
surv = read.delim('TCGA-LUAD.survival.tsv',header = T) 
library(tidyverse)
meta = left_join(surv,clinical,by = c("sample"= "submitter_id.samples"))
head(meta[,1:4])
tail(meta[,1:4]) 
print(dim(meta))
 
#去掉生存信息不全或者生存时间小于30天的样本,样本纳排标准不唯一,且差别很大.
k1 = meta$OS.time >= 30
k2 = !(is.na(meta$OS.time)|is.na(meta$OS))
meta = meta[k1&k2,]
meta = meta[,c(
  'sample',
  'OS',
  'OS.time'
)]
colnames(meta)=c('ID','event','time')
meta$time = meta$time/30
rownames(meta) <- meta$ID
s = intersect(rownames(meta),colnames(exprSet))
exprSet = exprSet[,s]
meta = meta[s,]
identical(rownames(meta),colnames(exprSet))
save(exprSet,meta,file = paste0(proj,".for_survival.rdata") ) 

前面的表达量矩阵跟临床生存分析已经是对应好了,就可以进行后续的生存分析啦

第3步:批量cox分析

这个代码也是七年前的了,蛮简单的的一个循环而已

代码语言:javascript
复制
rm(list=ls())
library(survival)
library(survminer) 
library(ggstatsplot) 
proj='tcga-luad'
load(file = paste0(proj,".for_survival.rdata") )

# 1. prepare data for coxph----
## 批量生存分析使用coxph回归方法 
exprSet[1:4,1:4]
phe=meta
head(phe)
mySurv <- with(phe, Surv(time, event))
survival_dat=phe 

cox_results <-apply(exprSet , 1 , function(gene){
  # gene= as.numeric(exprSet[1,]) 
  group=ifelse(gene>median(gene),'high','low') 
  group=factor(  group,levels = c('low','high'))
  if( length(table(group))<2)
    return(NULL)
  survival_dat <- data.frame(group=group,# stage=phe$stage,
                             stringsAsFactors = F)
  
  m=coxph(mySurv ~ group, 
          # mySurv ~  stage+ group,  # 如果有交叉变量
          data =  survival_dat)
  
  beta <- coef(m)
  se <- sqrt(diag(vcov(m)))
  HR <- exp(beta)
  HRse <- HR * se
  
  #summary(m)
  tmp <- round(cbind(coef = beta, se = se, z = beta/se, 
                     p = 1 - pchisq((beta/se)^2, 1),
                     HR = HR, HRse = HRse,
                     HRz = (HR - 1) / HRse, HRp = 1 - pchisq(((HR - 1)/HRse)^2, 1),
                     HRCILL = exp(beta - qnorm(.975, 0, 1) * se),
                     HRCIUL = exp(beta + qnorm(.975, 0, 1) * se)), 3)
  return(tmp['grouphigh',])
  
})

# 2. specify the value----
cox_results=t(cox_results)
head(cox_results)
cox_results=cox_results[order(cox_results[,'HR'],decreasing = T),]

table(cox_results[,4]<0.01)
table(cox_results[,4]<0.05) 
save(cox_results, 
     file = 'batch_cox_results.Rdata')
load(     file = 'batch_cox_results.Rdata') 

值得注意的是结果矩阵里面很多基因的HR值非常离谱,其实是因为这个基因在样品队列里面的表达量失衡,比如它仅仅是在少量的几个预后非常差的病人里面有表达量在所有的其它病人里面都是0值,这样的生存分析结果大概率是不可靠的!

基于单细胞转录组的生存分析

第1步:根据单细胞亚群基因集在肿瘤病人表达量矩阵里面进行gsva打分

如果是想看单个基因是否有统计学显著的生存分析意义其实前面的批量cox分析就可以提取结果了,但是我们的单细胞亚群基因集结果里面的基本上每个亚群都是几十个高表达量特异性基因,详见:换一个分析策略会导致文章的全部论点都得推倒重来吗,就知道如何输出如下所示的cosg_celltype__marker_cosg.Rdata文件啦:

代码语言:javascript
复制
rm(list=ls())
library(survival)
library(survminer) 
library(ggstatsplot) 
library(gplots)
library(ggplot2) 
library(pheatmap)
library(clusterProfiler) 
library(org.Hs.eg.db)
library(GSVA) 
library(GSEABase)
 
# 1. 载入表达量矩阵和临床信息 ----
proj='tcga-luad'
load(file = paste0(proj,".for_survival.rdata") ) 
exprSet[1:4,1:4]
phe=meta
head(phe)
mySurv <- with(phe, Surv(time, event))
survival_dat=phe

# 2. creat geneset----
# load('../../paper-figures/cosg_celltype__marker_cosg.Rdata')
load('cosg_celltype__marker_cosg.Rdata')
head(marker_cosg$names)
deg_list =  as.list(marker_cosg$names)
names(deg_list)
deg_list
gs = lapply(deg_list, toupper) 
geneset <- GeneSetCollection(mapply(function(geneIds, keggId) {
  GeneSet(geneIds, geneIdType=EntrezIdentifier(),
          collectionType=KEGGCollection(keggId),
          setName=keggId)
}, gs, names(gs)))
geneset

# 3. run gsva----
X=as.matrix(exprSet)
es.max <- gsva(X, geneset, 
               mx.diff=FALSE, verbose=FALSE, 
               parallel.sz=4)
es.max[1:4, 1:4] 
pheatmap(es.max) 

第2步:根据gsva打分值高低分组进行生存分析

一般来说, 就是根据gsva打分的中位值高低分组进行生存分析,代码如下所示:

代码语言:javascript
复制
# 4. 根据gsva结果高低分组后批量生存分析 ----
es.max[1:4, 1:4]
splots <- list()
g = 1
for (i in  names(deg_list) ) {
  # i =  names(deg_list) [1]
  subset = paste0('cluster_',i)
  print(subset)
  v = as.numeric(es.max[i,])   #每一个亚群表达量。
  sub_group <- ifelse( v < 0,"low","high")   #如果表达量小于0的话,就定义为low。gsva处理过表达量。0.几左右
  table(sub_group) 
  phe$sub_group=sub_group
  # Fit survival curves
  require("survival")
  fit <- survfit(Surv(time, event) ~ sub_group, data = phe)
  library("survminer")
  survp <- ggsurvplot(fit, data = phe,
                      surv.median.line = "hv", # Add medians survival
                      pval = TRUE,             # Add p-value and tervals 
                      conf.int = TRUE,        # Add the 95% confidence band
                      risk.table = TRUE,      # Add risk table
                      tables.height = 0.2,
                      tables.theme = theme_cleantable(),
                      palette = "jco",
                      ggtheme = theme_bw(),
                      title = subset)
  print(survp)
  splots[[g]] <-  survp
  g = g + 1
}

length(splots)
x1 = ceiling(sqrt(length(splots)))
y1 = x1

all_plot <- arrange_ggsurvplots(splots,
                                print = F,
                                ncol = x1, nrow = y1,
                                risk.table.height = 0.3,
                                surv.plot.height = 0.7)
# all_plot 
x2=5*x1
y2=5*y1
prefix=''
pro=''
ggsave(all_plot, #path = prefix,
       filename = paste0(pro, 'all_survival_plot.pdf'),
       width = x2,height = y2)

就可以看到如下所示的每个单细胞亚群的生存分析结果,很明显跟文章类似的,也是增殖亚群(UBE2C+) 它这个亚群的基因可以在tcga数据库的luad数据集里面的有统计学显著的生存分析意义。

生存分析意义

第3步:根据gsva打分值进行取巧分组进行生存分析

如果是上面的根据gsva打分的中位值高低分组进行生存分析都没有生存分析统计学显著意义,但是又想看看每个亚群的具体的到底是保护因子还是风险因子,也可以使用surv_cutpoint函数哦:

代码语言:javascript
复制
## cut point
## cutpoint
head(phe)
csplots <- list()
cg = 1
for (i in  names(deg_list) ) {
  # i =  names(deg_list) [1]
  subset = paste0('cluster_',i)
  print(subset)
  v = as.numeric(es.max[i,])   #每一个亚群表达量。
  phe$v <- v
  head(phe)
  sur.cut <- surv_cutpoint(phe,
                           time= 'time',
                           event = 'event' ,
                           variables = 'v' )
  sur.cat <- surv_categorize(sur.cut)
  head(sur.cat)
  sfit <- survfit(Surv(time, event) ~ v, data = sur.cat)
  p_surv_cut <- ggsurvplot(sfit, data = phe,
                           surv.median.line = "hv", # Add medians survival
                           pval = TRUE,             # Add p-value and tervals 
                           conf.int = TRUE,        # Add the 95% confidence band
                           risk.table = TRUE,      # Add risk table
                           tables.height = 0.2,
                           tables.theme = theme_cleantable(),
                           palette = "jco",
                           ggtheme = theme_bw(),
                           title = subset)
  print(p_surv_cut)
  csplots[[cg]] <-  p_surv_cut
  cg = cg + 1
}

length(csplots)
x1 = ceiling(sqrt(length(csplots)))
y1 = x1

all_plot <- arrange_ggsurvplots(csplots,
                                print = F,
                                ncol = x1, nrow = y1,
                                risk.table.height = 0.3,
                                surv.plot.height = 0.7)
# all_plot 
x2=5*x1
y2=5*y1
ggsave(all_plot, #path = prefix,
       filename = paste0(pro, 'all_cut_point_survival_plot.pdf'),width = x2,height = y2)



因为它并不是中位值高低分组,所以两个分组的病人数量是不平衡的, 如下所示:

数量是不平衡的

很明显可以看到,它取巧了,所以基本上可以让每个单细胞亚群的特异性基因列表,都有统计学显著的生存分析结果哦!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-10-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 生信技能树 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 生存分析三步走
    • 第1步:格式化表达量矩阵文件
      • 第2步:整理临床信息
        • 第3步:批量cox分析
        • 基于单细胞转录组的生存分析
          • 第1步:根据单细胞亚群基因集在肿瘤病人表达量矩阵里面进行gsva打分
            • 第2步:根据gsva打分值高低分组进行生存分析
              • 第3步:根据gsva打分值进行取巧分组进行生存分析
              相关产品与服务
              数据库
              云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档