使用MultiAssayExperiment结构探索TCGA数据

2022-07-26 10:06:16 浏览数 (1)

前面我们提到过一个bioconductor包居然发在了《cancer research》杂志,该文章 标题是:《Software for the Integration of Multiomics Experiments in Bioconductor》,文章链接是:https://cancerres.aacrjournals.org/content/77/21/e39

其bioconductor 链接是:https://bioconductor.org/packages/release/bioc/html/MultiAssayExperiment.html

主要是定义了一个数据结构(S4对象),如下所示:

MultiAssayExperiment结构

S4对象基本上是R语言分水岭了,无论是理解并且使用它还是创造它,都是一个门槛,甚至我在讲解单细胞数据分析流程的时候,把S4对象的理解作为了基本功!

安装和加载R包相信已经无需我多说了:

代码语言:javascript复制
 BiocManager::install("curatedTCGAData")
 BiocManager::install("TCGAutils") 
library(curatedTCGAData)
library(MultiAssayExperiment)
library(TCGAutils)

首先查看TCGA数据库有哪些数据

代码如下:

代码语言:javascript复制
data('diseaseCodes', package = "TCGAutils")
head(diseaseCodes)

可以看到是居然是37个数据集,但是有分子分型的并不多:

37个数据集

主要的癌症简称,以及其各个癌症内部的数据集形式,如下所示:

代码语言:javascript复制

Available Cancer codes:
 ACC BLCA BRCA CESC CHOL COAD DLBC ESCA GBM HNSC KICH
 KIRC KIRP LAML LGG LIHC LUAD LUSC MESO OV PAAD PCPG
 PRAD READ SARC SKCM STAD TGCT THCA THYM UCEC UCS UVM 
 
Available Data Types:
 CNACGH CNACGH_CGH_hg_244a
 CNACGH_CGH_hg_415k_g4124a CNASeq CNASNP
 CNVSNP GISTIC_AllByGene GISTIC_Peaks
 GISTIC_ThresholdedByGene Methylation
 Methylation_methyl27 Methylation_methyl450
 miRNAArray miRNASeqGene mRNAArray
 mRNAArray_huex mRNAArray_TX_g4502a
 mRNAArray_TX_g4502a_1
 mRNAArray_TX_ht_hg_u133a Mutation
 RNASeq2GeneNorm RNASeqGene RPPAArray 

多种癌症,多种数据类型。也是需要联网下载数据,但是可以使用 dry.run 控制是否真的下载,因为如果是下载甲基化信号值矩阵或者表达量矩阵,会耗时很长。

获取突变信息和拷贝数信息

因为下载甲基化信号值矩阵或者表达量矩阵,会耗时很长,所以我们拿简单的突变信息和拷贝数信息举例。

代码语言:javascript复制
(accmae <- curatedTCGAData(
  "ACC", c("CN*", "Mutation"), version = "2.0.1", dry.run = FALSE
))
accmae

得到一个MultiAssayExperiment结构的变量,如下所示:

代码语言:javascript复制
> accmae
A MultiAssayExperiment object of 3 listed
 experiments with user-defined names and respective classes.
 Containing an ExperimentList class object of length 3:
 [1] ACC_CNASNP-20160128: RaggedExperiment with 79861 rows and 180 columns
 [2] ACC_CNVSNP-20160128: RaggedExperiment with 21052 rows and 180 columns
 [3] ACC_Mutation-20160128: RaggedExperiment with 20166 rows and 90 columns
Functionality:
 experiments() - obtain the ExperimentList instance
 colData() - the primary/phenotype DataFrame
 sampleMap() - the sample coordination DataFrame
 `$`, `[`, `[[` - extract colData columns, subset, or experiment
 *Format() - convert into a long or wide DataFrame
 assays() - convert ExperimentList to a SimpleList of matrices
 exportClass() - save all data to files

可以看到我们前面的 参数 c("CN*", "Mutation"), 设置了可以下载一个突变信息文件,和两个拷贝数信息文件。因为在线下载,所以仍然是取决于网络速度哦。

探索临床信息

前面的MultiAssayExperiment结构的变量,可以被很多函数来处理,包括 getSubtypeMap 和 sampleTables。我们的突变信息和两个拷贝数信息,都需要有临床信息才能进行生物学意义探索。

如下所示:

代码语言:javascript复制
> head(getSubtypeMap(accmae)) 
        ACC_annotations   ACC_subtype
1            Patient_ID     patientID
2 histological_subtypes     Histology
3         mrna_subtypes       C1A/C1B
4         mrna_subtypes       mRNA_K4
5                  cimp    MethyLevel
6     microrna_subtypes miRNA cluster

> sampleTables(accmae)
$`ACC_CNASNP-20160128`

01 10 11 
90 85  5 

$`ACC_CNVSNP-20160128`

01 10 11 
90 85  5 

$`ACC_Mutation-20160128`

01 
90 

可以看到一个突变信息文件里面仅仅是记录了ACC这个癌症的全部的病人,而两个拷贝数信息文件是包含了ACC癌症的病人的正常组织和肿瘤组织。如果你对 01 和 10 不了解,也可以看看备忘录。

代码语言:javascript复制
data(sampleTypes, package = "TCGAutils")
head(sampleTypes)
sampleTypes[sampleTypes[["Code"]] %in% c("01", "10"), ]

可以看到:

代码语言:javascript复制
> sampleTypes[sampleTypes[["Code"]] %in% c("01", "10"), ]
   Code           Definition Short.Letter.Code
1    01  Primary Solid Tumor                TP
10   10 Blood Derived Normal                NB

前面的 01 10 11 代表 是否是肿瘤样品,就可以提取肿瘤相关数据:

代码语言:javascript复制
splitAssays(accmae, c("01", "10")) 
tums <- TCGAsampleSelect(colnames(accmae), "01")
accmae[, tums, ]

只需要 exportClass 函数即可,把前面的 MultiAssayExperiment对象 里面的数据写出来。

代码语言:javascript复制
exportClass(accmae, dir = './', fmt = "csv", ext = ".csv")
Writing about 7 files to disk...
[1] ".//accmae_META_0.csv"               
[2] ".//accmae_META_1.csv"               
[3] ".//accmae_ACC_CNASNP-20160128.csv"  
[4] ".//accmae_ACC_CNVSNP-20160128.csv"  
[5] ".//accmae_ACC_Mutation-20160128.csv"
[6] ".//accmae_colData.csv"              
[7] ".//accmae_sampleMap.csv"  

也可以获取临床信息;

代码语言:javascript复制
> ## -----------------------------------------------------------------------------
> head(getClinicalNames("ACC")) 
[1] "years_to_birth"        "vital_status"          "days_to_death"        
[4] "days_to_last_followup" "tumor_tissue_site"     "pathologic_stage"     
> colData(accmae)[, getClinicalNames("ACC")][1:5, 1:3] 
DataFrame with 5 rows and 3 columns
             years_to_birth vital_status days_to_death
                  <integer>    <integer>     <integer>
TCGA-OR-A5J1             58            1          1355
TCGA-OR-A5J2             44            1          1677
TCGA-OR-A5J3             23            0            NA
TCGA-OR-A5J4             23            1           423
TCGA-OR-A5J5             30            1           365
> ## -----------------------------------------------------------------------------

一个实战:提取TCGA数据库的BRCA数据集的TNBC亚型的表达量矩阵

前面我们提到过,如果是下载甲基化信号值矩阵或者表达量矩阵,会耗时很长。如果是去ucsc的xena浏览器下载,是一个130M左右的压缩包文件。

代码语言:javascript复制
brca <- curatedTCGAData(diseaseCode = "BRCA", 
                        version = "2.0.1",
                        assays = "RNASeq2GeneNorm", FALSE)
 head(getSubtypeMap(brca )) 
 head(getClinicalNames("BRCA")) 

信息如下:

代码语言:javascript复制
> head(getSubtypeMap(brca )) 
      BRCA_annotations               BRCA_subtype
1           Patient_ID                  patientID
2        mrna_subtypes                 PAM50 mRNA
3        mrna_subtypes SigClust Unsupervised mRNA
4        mrna_subtypes    SigClust Intrinsic mRNA
5    microrna_subtypes             miRNA Clusters
6 methylation_subtypes       methylation Clusters
> head(getClinicalNames("BRCA")) 
[1] "years_to_birth"        "vital_status"          "days_to_death"        
[4] "days_to_last_followup" "tumor_tissue_site"     "pathologic_stage"  

简单的搜索一下 ER.Status , PR.Status ,HER2.Final.Status

代码语言:javascript复制
 phe=as.data.frame(colData( brca ))
 
 #  Gender Age.at.Initial.Pathologic.Diagnosis   ER.Status   PR.Status HER2.Final.Status  
 
> head( phe[,colnames(phe)[grep('Status', colnames(phe),ignore.case = T)][56:59] ])
             ER.Status PR.Status HER2.Final.Status Vital.Status
TCGA-A1-A0SB  Positive  Negative          Negative       LIVING
TCGA-A1-A0SD  Positive  Positive          Negative       LIVING
TCGA-A1-A0SE  Positive  Positive          Negative       LIVING
TCGA-A1-A0SF  Positive  Positive          Negative       LIVING
TCGA-A1-A0SG  Positive  Positive          Negative       LIVING
TCGA-A1-A0SH  Negative  Positive          Negative       LIVING

这样的话,就可以根据 ER.Status , PR.Status ,HER2.Final.Status 这3个信息来判断TNBC样品,进而去筛选前面的表达量矩阵啦。

整体评价:用起来还行,但也不是非他不可!

一个分类模型

如果是分类模型构建,比如我们的模型希望是可以根据转录组测序的表达量来区分肿瘤样品和正常组织,获取数据的代码如下:

代码语言:javascript复制
library(curatedTCGAData)
library(TCGAutils)
params <- list(seed = 29221)

brca <- curatedTCGAData(diseaseCode = "BRCA", 
                        version = "2.0.1",
                        assays = "RNASeq2GeneNorm", FALSE)

## ----data.show, warning=FALSE, error=FALSE------------------------------------
brca <- TCGAutils::splitAssays(brca, c('01','11'))
xdata.raw <- t(cbind(assay(brca[[1]]), assay(brca[[2]])))
library(dplyr)
# Get matches between survival and assay data
class.v        <- TCGAbiospec(rownames(xdata.raw))$sample_definition %>% factor
names(class.v) <- rownames(xdata.raw)
# keep features with standard deviation > 0
xdata.raw <- xdata.raw %>%
  { (apply(., 2, sd) != 0) } %>%
  { xdata.raw[, .] } %>%
  scale

set.seed(params$seed)
small.subset <- c('CD5', 'CSF2RB', 'HSF1', 'IRGC', 'LRRC37A6P', 'NEUROG2',
                  'NLRC4', 'PDE11A', 'PIK3CB', 'QARS', 'RPGRIP1L', 'SDC1',
                  'TMEM31', 'YME1L1', 'ZBTB11',
                  sample(colnames(xdata.raw), 100))

xdata <- xdata.raw[, small.subset[small.subset %in% colnames(xdata.raw)]]
ydata <- class.v
save(xdata,ydata,file = 'brca_for_lasso.rdata')

上面的代码需要在线下载。

可以看到 肿瘤样品大概是正常样品的10倍数量。

代码语言:javascript复制
 
> table(ydata)
ydata
Primary Solid Tumor Solid Tissue Normal
               1093                 112

有了上面的乳腺癌患者的正常组织以及肿瘤样品的表达量矩阵数据,接下来就可以使用函数cv.glmHub来处理xdata和ydata即可进行lasso回归。

如果ydata存的是肿瘤或者正常样品这样的属性,我们使用cv.glmHub来做分类模型构建,如果ydata存的是肿瘤生存信息,那么我们使用cv.glmHub来做生存分析的模型构建。

代码语言:javascript复制
library(dplyr)
library(ggplot2)
library(survival)
library(loose.rock)
library(futile.logger)
library(curatedTCGAData)
library(TCGAutils)
library(glmSparseNet)

因为前面ydata存的是肿瘤或者正常样品这样的属性,是二分类,使用函数cv.glmHub 一句话代码即可完成分析:

代码语言:javascript复制
load('brca_for_lasso.rdata')  
table(ydata)
fitted <- cv.glmHub(xdata, ydata,
                    family  = 'binomial',
                    network = 'correlation',
                    nlambda = 1000,
                    network.options = networkOptions(cutoff = .6,
                                                     min.degree = .2))

plot(fitted)
resp <- predict(fitted, s = 'lambda.min', newx = xdata, type = 'class')
table(resp,ydata)

关键的参数是 family = 'binomial',这个参数告诉我们函数这个时候使用的分类模型。然后可以看到,这个分类器效果还不错:

代码语言:javascript复制
> table(resp,ydata)
                     ydata
resp                  Primary Solid Tumor Solid Tissue Normal
  Primary Solid Tumor                1089                   7
  Solid Tissue Normal                   4                 105

基本上没有分错的样品,当然了,还可以去提取构建好的分类器的基因,以及绘制ROC曲线等等,是另外的知识点了,这里仅仅是分享代码:

代码语言:javascript复制
coefs.v <- coef(fitted, s = 'lambda.min')[,1] %>% { .[. != 0]}
coefs.v %>% {
  data.frame(ensembl.id  = names(.),
             gene.name   = geneNames(names(.))$external_gene_name,
             coefficient = .,
             stringsAsFactors = FALSE)
} %>%
  arrange(gene.name) %>%
  knitr::kable()


flog.info('Misclassified (%d)', sum(ydata != resp))
flog.info('  * False primary solid tumour: %d',
          sum(resp != ydata & resp == 'Primary Solid Tumor'))
flog.info('  * False normal              : %d',
          sum(resp != ydata & resp == 'Solid Tissue Normal'))

## ----predict, echo=FALSE, warning=FALSE---------------------------------------
response <- predict(fitted, s = 'lambda.min', newx = xdata, type = 'response')
qplot(response, bins = 100)

## ----roc, echo=FALSE----------------------------------------------------------
roc_obj <- pROC::roc(ydata, as.vector(response))

data.frame(TPR = roc_obj$sensitivities, FPR = 1 - roc_obj$specificities) %>%
  ggplot()  geom_line(aes(FPR,TPR), color = 2, size = 1, alpha = 0.7) 
  labs(title= sprintf("ROC curve (AUC = %f)", pROC::auc(roc_obj)),
       x = "False Positive Rate (1-Specificity)",
       y = "True Positive Rate (Sensitivity)")

可以看到这个分类器的效果超级无敌的好:

分类器的效果超级无敌的好

上面的代码都是复制粘贴就可以运行的。

其实判断肿瘤样品和正常样品是比较容易的,因为肿瘤的特征非常明显,比如引用达到五位数的经典综述《hallmarks of cancer:the next generation》 里面的:

  • sustaining proliferative signaling:维持增殖信号
  • evading growth suppressors:逃避生长抑制
  • resisting cell death:抵抗细胞死亡
  • replicative immortality:复制无限
  • Angiogenesis:血管生成
  • invasion and metastasis:侵袭和转移
  • genome instability:基因组不稳定
  • Inflammation:炎症
  • reprogramming of energy metabolism:能量代谢重编程
  • evading immune destruction:逃避免疫破坏
  • tumor microenvironment:肿瘤微环境

0 人点赞