• 主页
  • 课程

    关于课程

    • 课程归档
    • 成为一名讲师
    • 讲师信息
    教学以及管理操作教程

    教学以及管理操作教程

    ¥1,000.00 ¥100.00
    阅读更多
  • 特色
    • 展示
    • 关于我们
    • 问答
  • 事件
  • 个性化
  • 博客
  • 联系
  • 站点资源
    有任何问题吗?
    (00) 123 456 789
    weinfoadmin@weinformatics.cn
    注册登录
    恒诺新知
    • 主页
    • 课程

      关于课程

      • 课程归档
      • 成为一名讲师
      • 讲师信息
      教学以及管理操作教程

      教学以及管理操作教程

      ¥1,000.00 ¥100.00
      阅读更多
    • 特色
      • 展示
      • 关于我们
      • 问答
    • 事件
    • 个性化
    • 博客
    • 联系
    • 站点资源

      生信星球

      • 首页
      • 博客
      • 生信星球
      • 转录组差异分析金标准-Limma-voom实战

      转录组差异分析金标准-Limma-voom实战

      • 发布者 weinfoeditor
      • 分类 生信星球
      • 日期 2020年6月19日
      测试开头

       [历史文章]那天是生信星球陪你的第304天


         大神一句话,菜鸟跑半年。我不是大神,但我可以缩短你走弯路的半年~

         就像歌儿唱的那样,如果你不知道该往哪儿走,就留在这学点生信好不好~

         这里有豆豆和花花的学习历程,从新手到进阶,生信路上有你有我!

      刘小泽写于19.3.11

      终于!之前的补上了,说到做到,并且不水,这就是豆花对生信星球的要求

      Limma作为差异分析的“金标准”最初是应用在芯片数据分析中,voom的功能是为了RNA-Seq的分析产生的。详细探索一下limma的功能吧

      本次的测试数据可以在公众号回复voom获得

      Limma-voom强大在于三个方面:

      • False discovery rate比较低(准确性),异常值影响小

      • 假阳性控制不错

      • 运算很快

      配置信息

      > library(edgeR)
      Loading required package: limma
      > counts <- read.delim("all_counts.txt", row.names = 1)
      > head(counts[1:3,1:3])
                C61 C62 C63
      AT1G01010 341 371 275
      AT1G01020 164  94 176
      AT1G03987   0   0   0
      > dim(counts)
      [1] 32833    24
      # 构建DGEList对象,将counts和sample信息包含进去
      > d0 <- DGEList(counts)

      预处理

      > # 计算标准化因子
      > d0 <- calcNormFactors(d0)
      > d0

      注意,这里的calcNormFactors并不是进行了标准化,仅仅是计算了一个参数,用于下游标准化

      # 过滤低表达基因[阈值根据自己需要设定]
      cutoff <- 1
      cut <- which(apply(cpm(d0), 1, max) < cutoff)
      d <- d0[-cut,] 
      dim(d) 
      [1] 21081    24
      # 剩下 21081个基因

      然后根据列名提取样本信息(sample name)

      > spname <- colnames(counts) 
      > spname
       [1] "C61"  "C62"  "C63"  "C64"  "C91"  "C92"  "C93" 
       [8] "C94"  "I561" "I562" "I563" "I564" "I591" "I592"
      [15] "I593" "I594" "I861" "I862" "I863" "I864" "I891"
      [22] "I892" "I893" "I894"

      看到样本是按照两个因素(品系C/I5/I8、时间6/9)分类的,并且四个生物学重复写在了最后C/I5/I8 | 6/9 | 1/2/3/4

      > # 分离出分组信息
      > strain <- substr(spname, 1, nchar(spname) - 2)
      > time <- substr(spname, nchar(spname) - 1, nchar(spname) - 1)
      > strain
       [1] "C"  "C"  "C"  "C"  "C"  "C"  "C"  "C"  "I5" "I5"
      [11] "I5" "I5" "I5" "I5" "I5" "I5" "I8" "I8" "I8" "I8"
      [21] "I8" "I8" "I8" "I8"
      > time
       [1] "6" "6" "6" "6" "9" "9" "9" "9" "6" "6" "6" "6"
      [13] "9" "9" "9" "9" "6" "6" "6" "6" "9" "9" "9" "9"

      再将这两部分整合进group分组信息中

      > # 再将这两部分整合进group分组信息中[生成因子型向量]
      > group <- interaction(strain, time)
      > group
       [1] C.6  C.6  C.6  C.6  C.9  C.9  C.9  C.9  I5.6 I5.6
      [11] I5.6 I5.6 I5.9 I5.9 I5.9 I5.9 I8.6 I8.6 I8.6 I8.6
      [21] I8.9 I8.9 I8.9 I8.9
      Levels: C.6 I5.6 I8.6 C.9 I5.9 I8.9

      当然,也可以自己手动输入或从其他文件导入,但必须注意一点:这个group metadata必须和counts的列明顺序对应

      多个实验因子同时存在时,要进行MDS(multidimensional scaling)分析,即“多维尺度变换”。正式差异分析前帮助我们判断潜在的差异样本,结果会将所有样本划分成几个维度,第一维度的样本代表了最大的差异

      > # Multidimensional scaling (MDS) plot
      > suppressMessages(library(RColorBrewer))
      > col.group <- group
      > levels(col.group) <- brewer.pal(nlevels(col.group), "Set1") 
      > col.group <- as.character(col.group)
      > plotMDS(d, labels=group, col=col.group) 
      > title(main="A. Sample groups")

      Voom转换及方差权重计算

      > mm <- model.matrix(~0 + group)
      > y <- voom(d, mm, plot = T)
      Good

      voom到底做了什么转换?

      首先原始counts转换成log2的CPM(counts per million reads ),这里的per million reads是根据之前calcNormFactors计算的norm.factors进行规定的;

      然后根据每个基因的log2CPM制作了线性模型,并计算了残差 ;

      然后利用了平均表达量(红线)拟合了sqrt(residual standard deviation);

      最后得到的平滑曲线可以用来得到每个基因和样本的权重

      https://genomebiology.biomedcentral.com/articles/10.1186/gb-2014-15-2-r29

      上图效果较好,如果像下面👇这样:就表示数据需要再进行过滤

      tmp <- voom(d0, mm, plot = T)
      Bad

      有时我们没有必要弄明白背后复杂的原理,只需要知道如何解释结果:

      https://stats.stackexchange.com/questions/160255/voom-mean-variance-trend-plot-how-to-interpret-the-plot

      limma-voom method assumes that rows with zero or very low counts have been removed

      如果横坐标接近0的位置出现迅速上升,说明low counts数比较多

      Whether your data are “good” or not cannot be determined from this plot

      limma的线性拟合模型构建

      > fit <- lmFit(y, mm)
      > head(coef(fit),3)
                groupC.6 groupI5.6 groupI8.6 groupC.9
      AT1G01010 4.685920 5.2477564  4.938939 4.922501
      AT1G01020 3.420726 3.4147535  3.130644 3.571855
      AT1G01030 1.111114 0.7316936  1.435521 1.157532
                groupI5.9 groupI8.9
      AT1G01010  5.382619  5.246093
      AT1G01020  3.610579  3.655254
      AT1G01030  0.388736  1.222892

      组间比较:

      例如进行I5品系的6和9小时比较

      > contr <- makeContrasts(groupI5.9 - groupI5.6, levels = colnames(coef(fit)))
      > contr
                 Contrasts
      Levels      groupI5.9 - groupI5.6
        groupC.6                      0
        groupI5.6                    -1
        groupI8.6                     0
        groupC.9                      0
        groupI5.9                     1
        groupI8.9                     0

      估算组间每个基因的比较:

      > tmp <- contrasts.fit(fit, contr)

      再利用Empirical Bayes (shrinks standard errors that are much larger or smaller than those from other genes towards the average standard erro)

      https://www.degruyter.com/doi/10.2202/1544-6115.1027

      > tmp <- eBayes(tmp)

      结果中差异基因有哪些呢?

      > top.table <- topTable(tmp, sort.by = "P", n = Inf)
      > DEG <- na.omit(top.table)
      > head(DEG, 5)
                    logFC  AveExpr         t      P.Value
      AT5G37260  3.163518 6.939588  23.94081 1.437434e-16
      AT3G02990  1.646438 3.190750  13.15656 1.610004e-11
      AT2G29500 -5.288998 5.471250 -11.94053 9.584101e-11
      AT3G24520  1.906690 5.780286  11.80461 1.179985e-10
      AT5G65630  1.070550 7.455294  10.86740 5.208111e-10
                   adj.P.Val        B
      AT5G37260 3.030255e-12 26.41860
      AT3G02990 1.697025e-07 15.50989
      AT2G29500 6.218818e-07 14.45441
      AT3G24520 6.218818e-07 14.52721
      AT5G65630 2.195844e-06 13.12701
      • logFC: log2 fold change of I5.9/I5.6

      • AveExpr: Average expression across all samples, in log2 CPM

      • t: logFC divided by its standard error

      • P.Value: Raw p-value (based on t) from test that logFC differs from 0

      • adj.P.Val: Benjamini-Hochberg false discovery rate adjusted p-value

      • B: log-odds that gene is DE (arguably less useful than the other columns)

      从前几个差异最显著的基因中可以看到,AT5G37260基因在time9的表达量最高(约time6的8倍),AT2G29500表达量最低,比time6的还少(约1/32)

      那么总共有多少差异基因呢?

      如果以logFC=2,Pvalue=0.05为阈值进行过滤

      > length(which(DEG$adj.P.Val < 0.05 & abs(DEG$logFC)>2 ))
      [1] 172

      如果要比较其他的组,例如:time6的品系C和品系I5

      只需要将makeContrasts修改

      contr <- makeContrasts(groupI5.6 - groupC.6, levels = colnames(coef(fit)))
      tmp <- contrasts.fit(fit, contr)
      tmp <- eBayes(tmp)
      top.table <- topTable(tmp, sort.by = "P", n = Inf)
      DEG <- na.omit(top.table)
      head(DEG, 5)
      length(which(DEG$adj.P.Val < 0.05 & abs(DEG$logFC)>2 ))
      # 结果只有8个

      上面利用了单因子group构建了model matrix,如果存在多个影响因子,可以利用新的因子(就省去了之前因子组合成group的步骤)构建新的矩阵模型

      # 构建新的model matrix
      > mm <- model.matrix(~strain*time)
      > colnames(mm)
      [1] "(Intercept)"    "strainI5"       "strainI8"      
      [4] "time9"          "strainI5:time9" "strainI8:time9"
      > y <- voom(d, mm, plot = F)
      > fit <- lmFit(y, mm)
      > head(coef(fit),3)
                (Intercept)     strainI5   strainI8
      AT1G01010    4.685920  0.561836365  0.2530188
      AT1G01020    3.420726 -0.005972208 -0.2900818
      AT1G01030    1.111114 -0.379420605  0.3244063
                    time9 strainI5:time9 strainI8:time9
      AT1G01010 0.2365808    -0.10171813     0.07057368
      AT1G01020 0.1511295     0.04469623     0.37348052
      AT1G01030 0.0464182    -0.38937581    -0.25904674
      • 算法自定义了标准品系为C,标准时间为6(可能是按照字母或数字顺序)

      • strainI5表示品系I5和标准品系(品系C)在标准时间点(time6)的差异

      • time9表示标准品系(品系C)在time9和time6的差异

      • strainI5:time9表示品系I5和品系C在time9和time6的差异(存在交叉影响)

      如果我们想比较品系I5和品系C在time6的差异,就可以:

      > tmp <- contrasts.fit(fit, coef = 2)
      > tmp <- eBayes(tmp)
      > top.table <- topTable(tmp, sort.by = "P", n = Inf)
      > DEG <- na.omit(top.table)
      > head(DEG, 5)
                     logFC    AveExpr          t
      AT4G12520 -10.254556  0.3581132 -11.402477
      AT3G30720   5.817438  3.3950689  10.528934
      AT5G26270   2.421030  4.3788335   9.654257
      AT3G33528  -4.780814 -1.8612945  -7.454943
      AT1G64795  -4.872595 -1.3119360  -7.079643
                     P.Value    adj.P.Val          B
      AT4G12520 2.206726e-10 4.651998e-06  3.6958152
      AT3G30720 9.108689e-10 9.601014e-06  7.9963406
      AT5G26270 4.101051e-09 2.881809e-05 10.8356224
      AT3G33528 2.741289e-07 1.444728e-03  0.5677732
      AT1G64795 5.985471e-07 2.523594e-03  1.8151705
      > length(which(DEG$adj.P.Val < 0.05 & abs(DEG$logFC)>2 ))
      [1] 8

      可以看到,和之前用单因子group得到的结果一样

      但是,这种方法在同时分析交叉影响时就体现出来强大了:

      比如我们想看time9与品系I5的差异结果

      > # cultivarI5:time9
      > tmp <- contrasts.fit(fit, coef = 5)
      > tmp <- eBayes(tmp)
      > top.table <- topTable(tmp, sort.by = "P", n = Inf)
      > DEG <- na.omit(top.table)
      > #head(DEG, 5)
      > length(which(DEG$adj.P.Val < 0.05 & abs(DEG$logFC)>2 ))
      [1] 111

      更复杂的模型

      有时RNA-Seq需要考虑批次效应(Batch effect)的影响

      > batch <- factor(rep(rep(1:2, each = 2), 6))
      > batch
       [1] 1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2
      Levels: 1 2

      构建模型时,需要将batch加在最后,其他不变

      > mm <- model.matrix(~0 + group + batch)
      > y <- voom(d, mm, plot = F)
      > fit <- lmFit(y, mm)
      > contr <- makeContrasts(groupI5.6 - groupC.6, levels = colnames(coef(fit)))
      > tmp <- contrasts.fit(fit, contr)
      > tmp <- eBayes(tmp)
      > top.table <- topTable(tmp, sort.by = "P", n = Inf)
      > DEG <- na.omit(top.table)
      > #head(DEG, 5)
      > length(which(DEG$adj.P.Val < 0.05 & abs(DEG$logFC)>2 ))
      [1] 9

      或者需要考虑其他因素的影响,比如这里有一个连续型变量rate,它可能是pH、光照等等对研究材料的影响值

      > # Generate example rate data[行数要与count矩阵的列数相等]
      > set.seed(10)
      > rate <- rnorm(n = 24, mean = 5, sd = 1.7)
      > rate
       [1] 5.031868 4.686771 2.668738 3.981415 5.500727
       [6] 5.662650 2.946271 4.381751 2.234656 4.563987
      [11] 6.873025 6.284829 4.595003 6.678656 6.260363
      [16] 5.151890 3.376595 4.668244 6.573386 5.821063
      > # 指定矩阵模型
      > mm <- model.matrix(~rate)
      > head(mm)
        (Intercept)     rate
      1           1 5.031868
      2           1 4.686771
      3           1 2.668738
      4           1 3.981415
      5           1 5.500727
      6           1 5.662650
      > y <- voom(d, mm, plot = F)
      > fit <- lmFit(y, mm)
      > tmp <- contrasts.fit(fit, coef = 2) # test "rate" coefficient
      > tmp <- eBayes(tmp)
      > top.table <- topTable(tmp, sort.by = "P", n = Inf)
      > DEG <- na.omit(top.table)
      > #head(DEG, 5)
      > length(which(DEG$adj.P.Val < 0.05 & abs(DEG$logFC)>2 ))
      [1] 0

      可见rate值并不能成为产生差异基因的原因,但是rate与基因的相关性还是可以探索一下的

      > AT1G01060 <- y$E["AT1G01060",]
      > plot(AT1G01060 ~ rate, ylim = c(6, 12))
      > intercept <- coef(fit)["AT1G01060", "(Intercept)"]
      > slope <- coef(fit)["AT1G01060", "rate"]
      > abline(a = intercept, b = slope)

      图中的斜率就是logFC值,或者可以说每单位rate的增加,gene表达量log2 CPM的改变。这里斜率为-0.096表示:每单位rate的增加,就有-0.096 log2CPM的基因表达量降低;或者每单位rate的增加,就有6.9%的CPM降低(2^0.096 = 1.069)


      点击底部的“阅读原文”,获得更好的阅读体验哦😻

      初学生信,很荣幸带你迈出第一步。

      我们是生信星球,一个不拽术语、通俗易懂的生信知识平台。由于是2018年新号,竟然没有留言功能。需要帮助或提出意见请后台留言、联系微信或发送邮件到jieandze1314@gmail.com,每一条都会看到的哦~


      转录组差异分析金标准-Limma-voom实战

      测试结尾

      请关注“恒诺新知”微信公众号,感谢“R语言“,”数据那些事儿“,”老俊俊的生信笔记“,”冷🈚️思“,“珞珈R”,“生信星球”的支持!

      • 分享:
      作者头像
      weinfoeditor

      上一篇文章

      我完善了那个R包,可以简化多组的差异分析啦
      2020年6月19日

      下一篇文章

      从mRNA开始的ceRNA网络构建
      2020年6月24日

      你可能也喜欢

      8-1651673488
      生信零基础入门学习小组长期报名中(2022仍继续)
      7 4月, 2022
      2-1651673738
      简化版的ROC曲线
      21 2月, 2022
      8-1651674718
      支持向量机模型
      19 11月, 2021

      搜索

      分类

      • R语言
      • TCGA数据挖掘
      • 单细胞RNA-seq测序
      • 在线会议直播预告与回放
      • 数据分析那些事儿分类
      • 未分类
      • 生信星球
      • 老俊俊的生信笔记

      投稿培训

      免费

      alphafold2培训

      免费

      群晖配置培训

      免费

      最新博文

      Nature | 单细胞技术揭示衰老细胞与肌肉再生
      301月2023
      lncRNA和miRNA生信分析系列讲座免费视频课和课件资源包,干货满满
      301月2023
      如何快速批量修改 Git 提交记录中的用户信息
      261月2023
      logo-eduma-the-best-lms-wordpress-theme

      (00) 123 456 789

      weinfoadmin@weinformatics.cn

      恒诺新知

      • 关于我们
      • 博客
      • 联系
      • 成为一名讲师

      链接

      • 课程
      • 事件
      • 展示
      • 问答

      支持

      • 文档
      • 论坛
      • 语言包
      • 发行状态

      推荐

      • iHub汉语代码托管
      • iLAB耗材管理
      • WooCommerce
      • 丁香园论坛

      weinformatics 即 恒诺新知。ICP备案号:粤ICP备19129767号

      • 关于我们
      • 博客
      • 联系
      • 成为一名讲师

      要成为一名讲师吗?

      加入数以千计的演讲者获得100%课时费!

      现在开始

      用你的站点账户登录

      忘记密码?

      还不是会员? 现在注册

      注册新帐户

      已经拥有注册账户? 现在登录

      close
      会员购买 你还没有登录,请先登录
      • ¥99 VIP-1个月
      • ¥199 VIP-半年
      • ¥299 VIP-1年
      在线支付 激活码

      立即支付
      支付宝
      微信支付
      请使用 支付宝 或 微信 扫码支付
      登录
      注册|忘记密码?