美文网首页单细胞测序
【单细胞转录组 实战】三、rawCounts和rpkmNorma

【单细胞转录组 实战】三、rawCounts和rpkmNorma

作者: 佳奥 | 来源:发表于2022-08-31 15:58 被阅读0次

    这里是佳奥!我们开始解析作者提供的表达矩阵吧!

    本次的代码在这里:

    https://github.com/jmzeng1314/scRNA_smart_seq2
    

    下载.zip后解压,开始下游分析!

    1 安装R包

    rm(list = ls())
    Sys.setenv(R_MAX_NUM_DLLS=999) ##Sys.setenv修改环境设置,R的namespace是有上限的,如果导入包时超过这个上次就会报错,R_MAX_NUM_DLLS可以修改这个上限
    options(stringsAsFactors = F) ##options:允许用户对工作空间进行全局设置,stringsAsFactors防止R自动把字符串string的列辨认成factor
    
    if (!requireNamespace("BiocManager", quietly = TRUE)) 
      install.packages("BiocManager") ##判断是否存在BiocManager包,不存在的话安装
    
    library(BiocManager)
    BiocManager::install(c( 'scran'),ask = F,update = F)
      
    BiocManager::install("TxDb.Mmusculus.UCSC.mm10.knownGene",ask = F,update = F)
    BiocManager::install("org.Mm.eg.db",ask = F,update = F)
    BiocManager::install("genefu",ask = F,update = F)
    BiocManager::install("org.Hs.eg.db",ask = F,update = F)
    BiocManager::install("TxDb.Hsapiens.UCSC.hg38.knownGene",ask = F,update = F)
    
    install.packages("ggfortify")
    install.packages("FactoMineR")
    install.packages("factoextra")
    

    2 解析表达矩阵

    上面的是rawCounts表达矩阵,下面的是Normalized归一化后的表达矩阵。

    rpkm:单纯比较基因reads数量是没有意义的(测序量不一样,基因长度不一样,测序文库大小不一样),所以需要归一化。

    QQ截图20220831102110.png

    2.1 rawCounts矩阵

    ##载入表达矩阵
    a=read.table('../GSE111229_Mammary_Tumor_fibroblasts_768samples_rawCounts.txt.gz',
                   header = T ,sep = '\t')  ##把表达矩阵文件载入R,header=T :保留文件头部信息,seq='\t'以tap为分隔符
    
    ##每次都要检测数据
    a[1:6,1:4] #对于a矩阵取第1~6行,第1~4列
    
    ##读取RNA-seq的 counts 定量结果,表达矩阵需要进行简单的过滤
    dat=a[apply(a,1, function(x) sum(x>1) > floor(ncol(a)/50)),] 
    #筛选表达量合格的行(基因), 列(细胞)数不变
      
    ##ncol()返回矩阵的列数值;floor()四舍五入取整数;
    ##function() 定义一个函数;sum()求和
    #上面的apply()指令代表对矩阵a进行行计算,判断每行表达量>1的样本总个数,并筛选出细胞表达量合格的基因(行)
    #第一个参数是指要参与计算的矩阵——a
    #第二个参数是指按行计算还是按列计算,1——表示按行计算,2——按列计算;
    #第三个参数是指具体的运算参数,定义一个函数x(即表达量为x)
      
    #对每行中x>1的列(即样本数)求和,即得出的是每行中表达量大于1的样本数,
    #然后再筛选出大于floor(ncol(a)/50)的行,这样的行(基因)的细胞表达量才算合格
    #因为2%的细胞有表达量,所以对于768个细胞样本,每个行(基因)在细胞中的表达至少要有15.36(约等于15)个样本表达才算合格
    ## 2 % 的细胞有表达量
    
    ##这里是演示归一化如何计算的            
    dat[1:4,1:4]
    sum(dat[,3])
    #  0610007P14Rik in  SS2_15_0048_A5 
    log2(18*1000000/sum(dat[,3])+1)
    ## 18 -- > 6.459884  ## SS2_15_0048_A5
                
    ##归一化的一种选择,这里是CPM(count-per-million,每百万碱基中每个转录本的count值)
    ##CPM只对read count相对总reads数做了数量的均一化,去除文库大小差异。
    dat=log2(edgeR::cpm(dat)+1) 
     
    dat[1:4,1:4] 
                  SS2_15_0048_A3 SS2_15_0048_A6 SS2_15_0048_A5 SS2_15_0048_A4
    0610007P14Rik              0              0       6.459884       6.313884
    0610009B22Rik              0              0       0.000000       0.000000
    0610009L18Rik              0              0       0.000000       0.000000
    0610009O20Rik              0              0       2.544699       3.025273
    
    ##下面介绍一下 dist 函数
      x=1:10
      y=2*x
      z=rnorm(10)
      tmp=data.frame(x,y,z)
      dist(tmp)
      head(tmp)
      dist(t(tmp))
      cor(tmp)
      dist(t(scale(tmp)))
    ##可以看到dist函数计算样本直接距离和cor函数计算样本直接相关性,是完全不同的概念。虽然我都没有调它们两个函数的默认的参数。
    # 总结:
    # - dist函数计算行与行(样本)之间的距离
    # - cor函数计算列与列(样本)之间的相关性
    # - scale函数默认对每一列(样本)内部归一化
    # - 计算dist之前,最好是对每一个样本(列)进行scale一下
    
    ##层次聚类,近800细胞。
    ##原始表达矩阵转置后,细胞在行,所以计算的是细胞与细胞之间的距离。
    hc=hclust(dist(t(dat))) ##样本间层次聚类
    
    
    ## statquest 有详细讲解背后的统计学原理。
    class(hc)
    ?plot.hclust
    ## 查看说明书。
    plot(hc,labels = FALSE)
      
    #t:矩阵转置,行转列,列转行
    #分类时常常需要估算不同样本之间的相似性(Similarity Measurement)
    #这时通常采用的方法就是计算样本间“距离”(Distance)。
      
    #dist函数是R语言计算距离的主要函数。dist函数可以计算行与行两两间的距离。
    #所以之前的矩阵里面行是基因,转置后行是样本,因为我们要计算样本与样本之间的距离。
    #dist()函数计算变量间距离
    #hclust函数用来层次聚类
      
    clus = cutree(hc, 4)##对hclust()函数的聚类结果进行剪枝,即选择输出指定类别数的系谱聚类结果。
    group_list= as.factor(clus)##转换为因子属性
    table(group_list)##统计频数
    group_list
      1   2   3   4 
    312 300 121  35 
                
    ##提取批次信息
    colnames(dat) #取列名
    library(stringr)
    plate=str_split(colnames(dat),'_',simplify = T)[,3] #取列名,以'_'号分割,提取第三列。
    #str_split()函数可以分割字符串
    table(plate)            
    
    n_g = apply(a,2,function(x) sum(x>1)) #统计每个样本有表达的有多少行(基因)
    # 这里我们定义, reads数量大于1的那些基因为有表达,一般来说单细胞转录组过半数的基因是不会表达的。
    # 而且大部分单细胞转录组技术很烂,通常超过75%的基因都没办法检测到。
    
    df=data.frame(g=group_list,plate=plate,n_g=n_g) #新建数据框(细胞的属性信息)
      
    ##样本为行名,列分别为:样本分类信息,样本分组,样本表达的基因数【注意:不是表达量的和,而是种类数或者说个数】
      
    df$all='all' #添加列,列名为"all",没事意思,就是后面有需要
    metadata=df
    save(a,dat,df,file = '../input.Rdata') 
    ##保存a,dat,df这变量到上级目录的input.Rdata
    ##因为另外一个项目也需要使用这个数据集,所以保存到了上级目录。
    
    ##查看一下n_g
    hist(n_g)
    hist(n_g,breaks = 30)            
    
    QQ截图20220831111603.png

    2.2 rpkmNormalized矩阵

    rm(list = ls())
    options(stringsAsFactors = F) 
     a=read.table('../GSE111229_Mammary_Tumor_fibroblasts_768samples_rpkmNormalized.txt.gz',header = T ,sep = '\t')  
    ##把表达矩阵文件载入R,header=T :保留文件头部信息,seq='\t'以tap为分隔符
    
    ##每次都要检测数据
    a[1:6,1:4] #对于a矩阵取第1~6行,第1~4列
    ## 读取RNA-seq的 counts 定量结果,表达矩阵需要进行简单的过滤
    dat=a[apply(a,1, function(x) sum(x>0) > floor(ncol(a)/50)),] #筛选表达量合格的行,列数不变
     
    dat[1:4,1:4]   
    #层次聚类
    hc=hclust(dist(t(log(dat+0.1)))) ##样本间层次聚类
    ##如果是基因聚类,可以选择 wgcna 等算法 
    
    ## statquest 
    plot(hc,labels = F)
    clus = cutree(hc, 4) #对hclust()函数的聚类结果进行剪枝,即选择输出指定类别数的系谱聚类结果。
    group_list= as.factor(clus) ##转换为因子属性
    table(group_list) ##统计频数
    group_list
      1   2   3   4 
    344 189 217  18            
    
    QQ截图20220831125306.png
    ##提取批次信息
    colnames(dat) #取列名
    library(stringr)
    plate=str_split(colnames(dat),'_',simplify = T)[,3] #取列名,以'_'号分割,提取第三列。
    #str_split()函数可以分割字符串
    table(plate)
      
    n_g = apply(a,2,function(x) sum(x>0)) #统计每个样本有表达的有多少行(基因)
    # 这里我们定义, reads数量大于1的那些基因为有表达,一般来说单细胞转录组过半数的基因是不会表达的。
    # 而且大部分单细胞转录组技术很烂,通常超过75%的基因都没办法检测到。
      
    df=data.frame(g=group_list,plate=plate,n_g=n_g) #新建数据框(细胞的属性信息)
      
    ##(样本为行名,列分别为:样本分类信息,样本分组,样本表达的基因数【注意:不是表达量的和,而是种类数或者说个数】)
      
    df$all='all' #添加列,列名为"all",后面有需要
    metadata=df
    save(dat,metadata,file = '../input_rpkm.Rdata') #保存dat,df这变量到上级目录的input_rpkm.Rdata
    ##因为另外一个项目也需要使用这个数据集,所以保存到了上级目录。
    

    3 表达矩阵内部异质性

    初步处理了表达矩阵,我们开始正式的分析探索。

    文章的图都是基于rpkm值来画的。

    3.1 rawCounts矩阵

    load(file = '../input.Rdata')
    a[1:4,1:4]
    head(df) #head()函数显示操作前面的信息,默认前6行
      
    ## 载入第0步准备好的表达矩阵,及细胞的一些属性(hclust分群,plate批次,检测到的基因数量)
    ##注意:变量a是原始的counts矩阵,变量dat是log2CPM后的表达量矩阵。
      
     group_list=df$g #'$'符,取列,取metadata矩阵的g列,取出层级聚类信息
     table(group_list) ##这是全部基因集的聚类分组信息
      
     cg=names(tail(sort(apply(dat,1,sd)),100)) ##取表达量标准差最大的100行的行名
     #这个前面演示过一次,dat=a[apply(a,1, function(x) sum(x>1) > floor(ncol(a)/50)),] #筛选表达量合格的行,列数不变
      
    #对dat矩阵每行求标准差,排序,取最后的100行,并获得后100行的行名(探针名)
    #sd()求标准差,对dat矩阵每一行的counts求标准差
    #sort()函数,排序;
    #tail()函数,显示操作对象后面的信息,默认后6行,这里设定取后100行
    #names()函数,获取或设置对象的名称
    
    library(pheatmap)
    ##画热图,针对top100的sd的基因集的表达矩阵,没有聚类分组
    pheatmap(dat[cg,],show_colnames =F,show_rownames = F)
    
    pheatmap(dat[cg,],show_colnames =F,show_rownames = F,
               filename = 'all_cells_top_100_sd.png')
    
    QQ截图20220831143434.png
    ##继续针对top100的sd的基因集的表达矩阵,归一化,分组画图
    
    ##这部分是示例,归一化不改变数据性质,但是改变数据分布(值域)
    x=1:10;plot((x))
    scale(x);plot(scale(x))
    
    #scale()函数去中心化和标准化    
    n=t(scale(t(dat[cg,])))
    ##对每个探针的表达量进行去中心化和标准化
    n[n>2]=2 #矩阵n中归一化后,大于2的项,赋值使之等于2(相当于设置了一个上限)
    n[n<-2]= -2 #小于-2的项,赋值使之等于-2(相当于设置了一个下限)
    n[1:4,1:4]
    
          SS2_15_0048_A3 SS2_15_0048_A6 SS2_15_0048_A5 SS2_15_0048_A4
    Kitl       0.9165638      1.2684450      1.4703938      0.6289595
    Mmp11     -2.0000000      0.3807272      0.5857658      0.1026709
    Atad1      0.4275134     -1.0657421      0.8755671     -1.0657421
    Btg2       0.7810682      0.9129418      0.7773478      1.4196704
    
    #pheatmap(n,show_colnames =F,show_rownames = F)
        
    ac=data.frame(g=group_list) #制作细胞(样本)分组矩阵
    rownames(ac)=colnames(n) ##ac的行名(样本名)等于n的列名(样本名)
    ##判断分组矩阵的行(样本数)和表达矩阵的列(样本数)是否相等
    pheatmap(n,show_colnames =F,show_rownames = F,
             annotation_col=ac)
    
    pheatmap(n,show_colnames =F,show_rownames = F,
             annotation_col=ac,
             filename = 'all_cells_top_100_sd_cutree1.png')
    
    QQ截图20220831144207.png
    ##针对top100的sd的基因集的表达矩阵 重新进行 聚类并且分组
       
    n=t(scale(t(dat[cg,])))
    n[n>2]=2
    n[n<-2]=-2
    n[1:4,1:4]
        
    ##这个聚类分组只是对top100的sd的基因集,从这里开始
    hc=hclust(dist(t(n))) 
    clus = cutree(hc, 4)
    group_list=as.factor(clus)
    table(group_list) ##这个聚类分组信息是针对top100的sd的基因集的,和针对全部基因集的分组结果不一样
    table(group_list,df$g) ## 其中 df$g 是前面步骤针对全部表达矩阵的层次聚类结果
        
    ##下面针对本次挑选100个基因的表达矩阵的层次聚类结果进行热图展示
    ac=data.frame(g=group_list)
    rownames(ac)=colnames(n)
    pheatmap(n,show_colnames = F,show_rownames = F,
            annotation_col=ac)
    
    pheatmap(n,show_colnames = F,show_rownames = F,
            annotation_col=ac,
            filename = 'all_cells_top_100_sd_cutree_2.png')
    
    dev.off() ##关闭画板
        
    ##先对整个基因集聚类分组,再对top100的sd的基因集画图
    ##和选取top100的sd的基因集,聚类分组再画图,结果聚类分组信息不同
    ##两次的聚类分组信息不同,画出的图不同
    
    QQ截图20220831145237.png

    3.2 PCA分析— rawCounts矩阵

    ##防止下面操作把数值搞坏的一个备份
    dat_back=dat
    dat=dat_back  ##表达矩阵数据
    dat[1:4,1:4]
    dat=t(dat)
    dat=as.data.frame(dat) ##转换为数据框
    dat=cbind(dat,group_list ) ##cbind()合并列(横向追加);添加分组信息
    dat[1:4,1:4]
    ## 表达矩阵可以随心所欲的取行列,基础知识需要打牢。
    dat[1:4,12197:12199]
    dat[,ncol(dat)] #ncol()列,返回列长值
    table(dat$group_list)
    
    library("FactoMineR")
    library("factoextra") 
    # The variable group_list (index = ) is removed
    # before PCA analysis
    ## 这里的PCA分析,被该R包包装成一个简单的函数,复杂的原理后面讲解。
    dat.pca <- PCA(dat[,-ncol(dat)], graph = FALSE) #'-'表示“非”
    
    fviz_pca_ind(dat.pca,repel =T,
                 geom.ind = "point", # show points only (nbut not "text")只显示点不显示文本
                 col.ind = dat$group_list, # color by groups 颜色组
                 # palette = c("#00AFBB", "#E7B800"),
                 addEllipses = TRUE, # Concentration ellipses 集中成椭圆
                 legend.title = "Groups")
    
    ## 事实上还是有很多基因dropout非常严重。
    ggsave('all_cells_PCA.png')
    
    QQ截图20220831152217.png

    3.3 rpkmNormalized矩阵

    rm(list = ls())
    options(stringsAsFactors = F)
    load(file = '../input_rpkm.Rdata')
    
    # a[1:4,1:4]
    dat[1:4,1:4]
    head(metadata) #head()函数显示操作前面的信息,默认前6行
      
    ##载入第0步准备好的表达矩阵,及细胞的一些属性(hclust分群,plate批次,检测到的基因数量)
    ##注意 变量a是原始的counts矩阵,变量 dat是log2CPM后的表达量矩阵。
      
    group_list=metadata$g #'$'符,取列,取metadata矩阵的g列,取出层级聚类信息
    table(group_list) ##这是全部基因集的聚类分组信息
      
    cg=names(tail(sort(apply(dat,1,sd)),100)) ##取表达量标准差最大的100行的行名
    # 这个前面演示过一次,dat=a[apply(a,1, function(x) sum(x>1) > floor(ncol(a)/50)),] #筛选表达量合格的行,列数不变
     
    #对dat矩阵每行求标准差,排序,取最后的100行,并获得后100行的行名(探针名)
    #sd()求标准差,对dat矩阵每一行的counts求标准差
    #sort()函数,排序;
    #tail()函数,显示操作对象后面的信息,默认后6行,这里设定取后100行
    #names()函数,获取或设置对象的名称
    library(pheatmap)
    
    ##后面要画热图,需要取对数,不然会被最大值覆盖掉
    mat=log2(dat[cg,]+0.01)
    
    ##画热图,针对top100的sd的基因集的表达矩阵,没有聚类分组
    pheatmap(mat,show_colnames =F,show_rownames = F)
    
    pheatmap(mat,show_colnames =F,show_rownames = F,
             filename = 'all_cells_top_100_sd.png')
    
    QQ截图20220831152744.png

    上图还是难以解释某些基因在细胞中的表达量是高还是低,难以区分(横向看颜色都差不多)。所以我们并不想知道原始表达量的高低,我们想知道该基因在不同样本表达的高低。

    ##针对top100的sd的基因集的表达矩阵,归一化,分组画图
        
    x=1:10;plot((x))
    scale(x);plot(scale(x))
        
    n=t(scale(t( mat ))) 
    #scale()函数去中心化和标准化
    ##对每个探针的表达量进行去中心化和标准化
    n[n>2]=2 #矩阵n中归一化后,大于2的项,赋值使之等于2(相当于设置了一个上限)
    n[n<-2]=-2 #小于-2的项,赋值使之等于-2(相当于设置了一个下限)
    n[1:4,1:4]
        
    # pheatmap(n,show_colnames =F,show_rownames = F)
    
    ac=data.frame(g=group_list) #制作细胞(样本)分组矩阵
    rownames(ac)=colnames(n) ##ac的行名(样本名)等于n的列名(样本名)
    ##判断分组矩阵的行(样本数)和表达矩阵的列(样本数)是否相等
    pheatmap(n,show_colnames =F,show_rownames = F,
                 annotation_col=ac)
    
    pheatmap(n,show_colnames =F,show_rownames = F,
                 annotation_col=ac,
                 filename = 'all_cells_top_100_sd_cutree1.png') 
    dev.off() ##关闭画板
    
    QQ截图20220831153042.png

    重新进行分组

    ## 针对top100的sd的基因集的表达矩阵 进行重新 聚类并且分组。
    
    n=t(scale(t( mat )))
    n[n>2]=2
    n[n<-2]= -2
    n[1:4,1:4]
        
    ##这个聚类分组只是对top100的sd的基因集
    hc=hclust(dist(t(n))) 
    clus = cutree(hc, 4)
    group_list=as.factor(clus)
    table(group_list) ##这个聚类分组信息是针对top100的sd的基因集的,和针对全部基因集的分组结果不一样
    table(group_list,metadata$g) ## 其中 metadata$g 是前面步骤针对全部表达矩阵的层次聚类结果。
        
    ## 下面针对本次挑选100个基因的表达矩阵的层次聚类结果进行热图展示。
    ac=data.frame(g=group_list)
    rownames(ac)=colnames(n)
    pheatmap(n,show_colnames =F,show_rownames = F,
             annotation_col=ac)
    
    pheatmap(n,show_colnames =F,show_rownames = F,
             annotation_col=ac,
             filename = 'all_cells_top_100_sd_cutree_2.png')
    dev.off() ##关闭画板
    
    QQ截图20220831154233.png

    3.4 PCA分析— rpkmNormalized矩阵

    dat_back=dat ##防止下面操作把数值搞坏的一个备份
    dat=dat_back  ##表达矩阵数据
    dat[1:4,1:4]
    dat=t(dat)
    dat=as.data.frame(dat) ##转换为数据框
    dat=cbind(dat,group_list ) ##cbind()合并列(横向追加);添加分组信息
    dat[1:4,1:4]
    
    dat[1:4,12197:12199]
    dat[,ncol(dat)] #ncol()列,返回列长值
    table(dat$group_list)
    
    library("FactoMineR")
    library("factoextra") 
    # The variable group_list (index = ) is removed
    # before PCA analysis
    ## 这里的PCA分析,被该R包包装成一个简单的函数,复杂的原理后面讲解。
    dat.pca <- PCA(dat[,-ncol(dat)], graph = FALSE) #'-'表示“非”
    fviz_pca_ind(dat.pca,repel =T,
                 geom.ind = "point", # show points only (nbut not "text")只显示点不显示文本
                 col.ind = dat$group_list, # color by groups 颜色组
                 # palette = c("#00AFBB", "#E7B800"),
                 addEllipses = TRUE, # Concentration ellipses 集中成椭圆
                 legend.title = "Groups")
    
    ## 事实上还是有很多基因dropout非常严重。
    ggsave('all_cells_PCA.png') 
    
    QQ截图20220831153403.png

    检查两个表达矩阵就到这里。

    下一篇我们开始复现第一张图——平均表达量以及变异系数相关散点图。

    我们下一篇再见!

    相关文章

      网友评论

        本文标题:【单细胞转录组 实战】三、rawCounts和rpkmNorma

        本文链接:https://www.haomeiwen.com/subject/liudnrtx.html