# 3.6 Marker/标记基因检测

## 1 前言

在上一章聚类分群的结尾，为了解释分群的结果，指定了几个基因进行区分，这几个基因就属于**marker基因或者叫标志基因**，它们是经过反复验证得到的。也就是说，一般看到相关的marker基因，就可以把某个cluster与某种细胞类型对应起来；另外这个思路还可以探索亚群之间发生的微小差异（例如通路激活、分化状态）与基因表达的联系

上面👆说的，主要还是验证，就是看看某个cluster到底是不是这个细胞类型，做这个的前提是你已经了解了你的细胞是什么类型，只是不确定。

对于常规流程来讲，更多的是探索，就是我们**得到了分群的结果，然后再怎么分析？怎么和marker基因联系起来？数万个基因，哪些才是这个cluster的marker基因？**

我们认为，导致cluster出现差异的那部分基因中，尤其是那些差异最显著的基因中，最可能包含marker基因。因此一个首要任务就是去进行cluster之间的差异分析，最后把每个cluster中最显著的前多少基因拿出来，放在一起（有没有想起来Seurat的那个热图？黑黄相间的那个）

### **下面还是使用10X PBMC数据**

这次就不从头开始处理了，如果想知道从数据读取到聚类之间的步骤，可以去看之前写的，里面有详细处理代码。这次直接加载聚类后的数据即可：`clustered.sce.pbmc.RData` 链接：<https://share.weiyun.com/4fOP3IDw> 密码：xswtct

```r
load('clustered.sce.pbmc.RData')
sce.pbmc
## class: SingleCellExperiment 
## dim: 33694 3922 
## metadata(1): Samples
## assays(2): counts logcounts
## rownames(33694): RP11-34P13.3 FAM138A ... AC213203.1 FAM231B
## rowData names(2): ID Symbol
## colnames(3922): AAACCTGAGAAGGCCT-1 AAACCTGAGACAGACC-1 ...
##   TTTGTCACAGGTCCAC-1 TTTGTCATCCCAAGAT-1
## colData names(4): Sample Barcode sizeFactor label
## reducedDimNames(3): PCA TSNE UMAP
## altExpNames(0):
```

## 2 检测方法

### **2.1 常规方法-t检验**

> `findMarkers()`提供了三种检验方法，分别是：t、wilcox、binom。默认使用t检验

针对大量细胞的检验，Welch t-test计算速度很快，并且有不错的统计学意义。使用`findMarkers()` 可以对每个基因在clusters之间进行两两比较，返回的列表中包括了每个cluster中排过序的候选marker基因

```r
library(scran)
markers.pbmc <- findMarkers(sce.pbmc)
markers.pbmc
## List of length 18
## names(18): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
```

`findMarkers()` 默认根据`sce.pbmc`中的`colLabels()`信息提取各个cluster，使用的就是`groups`参数，因此也可以写成：

```r
same.markers <- findMarkers(sce.pbmc, groups=colLabels(sce.pbmc))
```

有了这个参数，就可以根据其他方法的分群结果再去探索不一样的marker基因，而不用修改原始的`sce.pbmc`结果，只要`groups`参数满足与`sce.pbmc`列数一致就可以

**怎么解释这个结果呢？--以cluster9为例**

```r
chosen <- "9"
interesting <- markers.pbmc[[chosen]]
colnames(interesting)
##  [1] "Top"           "p.value"       "FDR"           "summary.logFC"
##  [5] "logFC.1"       "logFC.2"       "logFC.3"       "logFC.4"      
##  [9] "logFC.5"       "logFC.6"       "logFC.7"       "logFC.8"      
## [13] "logFC.10"      "logFC.11"      "logFC.12"      "logFC.13"     
## [17] "logFC.14"      "logFC.15"      "logFC.16"      "logFC.17"     
## [21] "logFC.18"
```

可以看到其中有很多logFC值，表示`log2(cluster9/other_cluster)`

`findMarkers()` 默认会根据第一列Top进行排序，而其中第一列”Top“指的是：cluster9中差异表达的前多少位基因。**但Top1不代表只有1个基因，而是可能有很多并列第一**，但为了区分，还是用pvalue给各个并列第一又排了顺序

```r
# 比如这里看到的，并列第一就不止10个
interesting[1:10,1:4] 
## DataFrame with 10 rows and 4 columns
##                Top      p.value          FDR summary.logFC
##          <integer>    <numeric>    <numeric>     <numeric>
## S100A4           1  3.29706e-57  3.05195e-55      -4.52198
## TAGLN2           1  1.65522e-24  3.58425e-23       4.83531
## PF4              1  2.54870e-35  9.99719e-34       5.91366
## GZMA             1 1.41952e-120 7.71441e-118      -1.95444
## HLA-DQA1         1  1.79189e-88  4.75402e-86      -3.64622
## FCN1             1 1.13468e-246 4.77901e-243      -2.81179
## SERPINA1         1  1.12795e-68  1.72751e-66      -2.43278
## RPL23A           1  2.42151e-37  1.04737e-35      -4.07367
## RPL17            1  0.00000e+00  0.00000e+00      -2.82856
## RPS21            1  1.08454e-56  9.90316e-55      -3.99499
```

知道了这个概念，提取cluster9中的Top6的所有基因也不是难事

```r
best.set <- interesting[interesting$Top <= 6,]
# 看到Top6其实总共有53个基因
> dim(best.set)
[1] 53 21
# 提取这些基因在与各个cluster比较时的logFC
logFCs <- getMarkerEffects(best.set)
# 总共18个cluster，除去自己还剩17个
> dim(logFCs)
[1] 53 17

> logFCs[1:4,1:4]
                1           2         3           4
S100A4 -2.7287830 -0.89602358 -2.887000 -4.33065808
TAGLN2  3.8690448  3.72075587  3.955002  4.14646142
PF4     6.0988107  6.10290759  6.103301  6.07864054
GZMA   -0.4340303 -0.09184649 -1.954439 -0.07511017 

library(pheatmap)
pheatmap(logFCs, breaks=seq(-5, 5, length.out=101))
```

![](https://jieandze1314-1255603621.cos.ap-guangzhou.myqcloud.com/blog/2020-07-03-091314.png)

看到其中platelet factor 4 (PF4) 与 pro-platelet basic protein (PPBP)基因表达量高，推测cluster9含有血小板或者它的前体

**除了Top这一列，还有一列叫”summary.logFC“**，它可以帮我们快速判断基因在cluster9中是上调还是下调，例如看PF4在这里的logFC值就很高

![](https://jieandze1314-1255603621.cos.ap-guangzhou.myqcloud.com/blog/2020-07-03-091940.png)

**不同的比较方法**

* 注意到，**这里使用的差异比较方法是”两两比较**“，即将一个cluster和其余各个cluster进行比较。
* 当然还有**其他方法是将一个cluster与其他剩余cluster的均值进行比较**。如果是与均值比较，那么就会细胞群体组成比较敏感，如果其中出现一个”支配欲超强的“cluster，那么它会把整个平均的表达水平带偏，结果看到的差异分析也并不准确。
* 另外，使用两两比较的方法还会提供有关marker基因更多的信息，比如能看到哪些clusters是由某个marker基因区分的

### **2.2 如果只关注上调基因**

之前`findMarkers`目的是选取上调、下调基因作为marker基因的候选，但其实下调基因很难吸引我们的注意力，**我们会首先关注图上红色的，也就是上调的基因们**。另一方面，相比于上调，下调基因也很难通过实验去验证。因此，如果只关心上调的基因，可以**使用单边t检验，**&#x5C06;某个cluster和其他clusters进行比较，设置参数`direction="up"`

```r
markers.pbmc.up <- findMarkers(sce.pbmc, direction="up")
interesting.up <- markers.pbmc.up[[chosen]]
interesting.up[1:10,1:4]
## DataFrame with 10 rows and 4 columns
##                 Top     p.value         FDR summary.logFC
##           <integer>   <numeric>   <numeric>     <numeric>
## TAGLN2            1 8.27609e-25 9.29516e-21       4.83531
## PF4               1 1.27435e-35 4.29379e-31       5.91366
## SDPR              2 2.26416e-21 1.90722e-17       4.72820
## GPX1              2 1.79269e-20 1.00671e-16       4.83143
## TMSB4X            2 1.61389e-31 2.71891e-27       3.71343
## PPBP              3 2.67043e-20 1.28539e-16       5.54885
## NRGN              3 1.41986e-20 9.56813e-17       4.18416
## CCL5              5 2.55331e-18 9.55903e-15       4.62327
## GNG11             6 2.06623e-18 8.70243e-15       4.73606
## HIST1H2AC         7 1.05437e-17 3.55260e-14       4.76160
```

另外还可以根据logFC阈值过滤，其实这些都可以自己手动过滤，多个参数只是更方便一点。缺点就是需要记住这个函数有这个参数

```r
markers.pbmc.up2 <- findMarkers(sce.pbmc, direction="up", lfc=1)
interesting.up2 <- markers.pbmc.up2[[chosen]]
interesting.up2[1:10,1:4]
```

根据两重过滤的结果（direction + logFC），再看cluster9的marker基因热图

```r
best.set <- interesting.up2[interesting.up2$Top <= 5,]
logFCs <- getMarkerEffects(best.set)

library(pheatmap)
pheatmap(logFCs, breaks=seq(-5, 5, length.out=101))
```

![](https://jieandze1314-1255603621.cos.ap-guangzhou.myqcloud.com/blog/2020-07-03-111225.png)

**注意**

* 我们这里只是探索了上调基因。至于有一些亚群中可能部分基因下调才导致这个亚群与众不同，这样的亚群这里检测不到
* 这里的阈值可能会漏掉一些改变幅度不大，但依然重要的基因

### **2.3 寻找cluster特异的marker基因**

> 上面提到，`findMarkers()` 会对两两比较结果做一个排名，然后选择p值比较显著的一些作为Top基因，返回的结果包括了所有cluster的logFC情况，比如这里有18个cluster，那么返回的结果也包含18个cluster的logFC。**以上调差异表达为例：**&#x67D0;个基因在cluster9与cluster1相比下上调，但这个基因在cluster9和cluster2中不上调，依然会把这个基因列出来

有一种**更严格的过滤机制**，就是只选在某个cluster与其他各个clusters相比都差异表达的基因，结果返回17个cluster（不包括自己）。**以上调差异表达为例**：结果得到的每个基因，不管是cluster9与cluster1比较，还是与cluster2比较，都是上调的；并且，这个基因仅仅在cluster9中是上调的

```r
# 设置pval.type="all"就是做了这件事，并且还是选上调的基因
markers.pbmc.up3 <- findMarkers(sce.pbmc, pval.type="all", direction="up")
# 然后就想看看感兴趣的cluster9与其他各个clusters比较后差异基因
interesting.up3 <- markers.pbmc.up3[[chosen]]
interesting.up3[1:10,1:3]
```

* 这种做法过于严格，以至于如果一个基因除了在cluster9中上调，还在cluster4中上调，这个基因就不会写进结果。【它的想法很简单，就是单纯针对cluster9，只找在它里面上调的】
* 另外，如果细胞分群效果不好，这样的寻找方法会过滤掉太多的潜在的感兴趣基因
* 举个例子：如果一群细胞混杂了单纯CD4+、单纯CD8+、二者都有、二者都无这四种情况。如果设置`pval.type="all"`，那么Cd4或Cd8基因都不会列入marker基因结果，因为它们都会在两个亚群有差异表达情况

还有另一种方法：`pval.type="any"` ，就是只要在一个cluster中出现差异表达，就写入结果。但这个设置有有点过于宽松，因此一个折中的方法：`pval.type="some"` ，各个方法得到的`summary.logFC`这一列都是不同的，基因排名前后也略有变化。

> 我相信大家可能并关心每个方法是怎么去比较，怎么去做统计的，更关心的是，我用了这个方法，得到的结果可用性有多高？这个问题可以思考一下，如果真的有一种普适性的方法，开发者又怎么会去设置这么多参数呢？直接一个参数到底，不是更方便？
>
> 数据分析就是这样，存在太多的不确定性。但只有我们使用一种方法感觉走不通了，才会意识到**多个参数多条路**的滋味。

### **2.4 除了t检验，还有Wilcoxon、binomial检验**

**首先来了解一下各种统计检验函数**

> 参考：<https://shixiangwang.github.io/home/cn/post/2019-12-25-r-stats-funs-summary/>

**对于连续型数据**

基于正态分布的检验：

* 均值检验：`t.test()`
* 两总体方差检验：`var.test()`
* 多个组间均值的比较（ANOVA）：`aov()`
* 多组样本的配对 t 检验：`pairwise.t.test()`
* 正态性检验：`shapiro.test()`&#x20;
* 分布的对称性检验：`ks.test()`
* 检验两个向量是否服从同一分布：`ks.test()`
* 相关性检验：`cor.test()`

不依赖分布的检验:

* 均值检验：Wilcoxon ，也就是说，Wilcoxon 检验是 t 检验的非参数版本。默认是秩和检验`wilcox.test`&#x20;
* 多均值比较：`kruskal.test()`  Kruskal-Wallis 秩和检验
* 方差检验：`fligner.test()` Fligner-Killeen（中位数）检验完成不同组别的方差比较
* 尺度参数差异：`ansari.test()` 针对两样本尺度参数差异的 Ansari-Bradley 检验；`mood.test()` 使用 Mood 两样本检验

**对于离散型数据**

* 比例检验：`prop.test()` 比较两组观测值发生的概率是否有差异
* 二项式检验：`binom.test()`&#x20;
* 列联表检验：`fisher.test()` 用来确定两个分类变量是否相关； 针对小的列联表，Fisher 精确检验效果不错；大列联表可以用卡方检验代替；检验三个变量的混合影响，可以用Cochran-Mantel-Haenszel 检验`mantelhaen.test()` ；McNemar 卡方可以检验二维列联表的对称性`mcnemar.test()`&#x20;
* 列联表非参数检验：Friedman 秩和检验（非参数的双边 ANOVA 检验） `friedman.test()`&#x20;

**找marker基因的Wilcoxon方法**

```r
markers.pbmc.wmw <- findMarkers(sce.pbmc, test="wilcox", direction="up")
names(markers.pbmc.wmw)
##  [1] "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9"  "10" "11" "12" "13" "14" "15"
## [16] "16" "17" "18"
interesting.wmw <- markers.pbmc.wmw[[chosen]]
interesting.wmw[1:10,1:4]
## DataFrame with 10 rows and 4 columns
##                 Top      p.value          FDR summary.AUC
##           <integer>    <numeric>    <numeric>   <numeric>
## PF4               1 3.13749e-164 1.05715e-159    0.988833
## TMSB4X            1  5.07215e-27  2.05905e-24    0.992149
## SDPR              2 2.12114e-145 3.57349e-141    0.955218
## NRGN              2 1.18240e-131 7.96793e-128    0.966119
## TAGLN2            3  1.55560e-28  6.98860e-26    0.967186
## PPBP              3 3.57148e-134 4.01125e-130    0.932743
## GNG11             3 2.46077e-126 1.38189e-122    0.932491
## TUBB1             3 7.55573e-133 6.36457e-129    0.921632
## HIST1H2AC         4  4.69094e-94  1.43688e-90    0.930973
## ACTB              5  1.53723e-23  5.28523e-21    0.949431
```

**找marker基因的binomial方法**

```r
markers.pbmc.binom <- findMarkers(sce.pbmc, test="binom", direction="up")
# 选出cluster9的marker基因
interesting.binom <- markers.pbmc.binom[[chosen]]
colnames(interesting.binom)
##  [1] "Top"           "p.value"       "FDR"           "summary.logFC"
##  [5] "logFC.1"       "logFC.2"       "logFC.3"       "logFC.4"      
##  [9] "logFC.5"       "logFC.6"       "logFC.7"       "logFC.8"      
## [13] "logFC.10"      "logFC.11"      "logFC.12"      "logFC.13"     
## [17] "logFC.14"      "logFC.15"      "logFC.16"      "logFC.17"     
## [21] "logFC.18"
library(scater)
top.genes <- head(rownames(interesting.binom))
plotExpression(sce.pbmc, x="label", features=top.genes)
```

![](https://jieandze1314-1255603621.cos.ap-guangzhou.myqcloud.com/blog/2020-07-05-055703.png)

### **2.5 整合多个统计分析的结果**

这样可以检验哪些基因是强有力的marker基因（能撑得住三大检验方法的考验）

```r
combined <- multiMarkerStats(
    t=findMarkers(sce.pbmc, direction="up"),
    wilcox=findMarkers(sce.pbmc, test="wilcox", direction="up"),
    binom=findMarkers(sce.pbmc, test="binom", direction="up")
)
> combined
List of length 18
names(18): 1 2 3 4 5 6 7 8 ... 12 13 14 15 16 17 18

head(combined[["9"]][,1:15])
```

![](https://jieandze1314-1255603621.cos.ap-guangzhou.myqcloud.com/blog/2020-07-05-061802.png)

当然也可以重点关注其中的某一个指标，比如wilcox的结果AUC越大，就表示基因表达量在各个cluster之间的分布越分散；t-test的logFC结果越大，表示更容易解释一个基因在两个cluster之间的变化幅度

## 3 另外，可以封锁一些不重要因素

大型数据集一般会涉及许多变化因素（比如批次、性别差异、年龄差异等等），它们会对数据波动产生影响，但又不是感兴趣的生物因素。如果在检测marker基因的时候带着它们，可能会结果产生干扰。

因此**有一个参数`block`可以帮我们”锁住“它们**，之后检测的时候就不会把这些因素纳入考量

```r
# 举个例子，在416b数据集中有批次因素，可以锁定
m.out <- findMarkers(sce.416b, block=sce.416b$block, direction="up") 
demo <- m.out[["1"]] 
# 前Top5的marker基因
demo[demo$Top <= 5,1:4]
## DataFrame with 13 rows and 4 columns
##                          Top     p.value         FDR summary.logFC
##                    <integer>   <numeric>   <numeric>     <numeric>
## Foxs1                      1 1.37387e-12 4.35563e-10       3.07058
## Pirb                       1 2.08277e-33 1.21332e-29       5.87820
## Myh11                      1 6.44327e-47 3.00282e-42       4.38182
## Tmsb4x                     2 3.22944e-44 7.52525e-40       1.47689
## Ctsd                       2 6.78109e-38 7.90065e-34       2.89152
## ...                      ...         ...         ...           ...
## Tob1                       4 6.63870e-09 1.18088e-06       2.74161
## Pi16                       4 1.69247e-32 7.88758e-29       5.76914
## Cd53                       5 1.08574e-27 2.97646e-24       5.75200
## Alox5ap                    5 1.33791e-28 4.15679e-25       1.36676
## CBFB-MYH11-mcherry         5 3.75556e-35 3.50049e-31       3.01677
```

这个参数对上面的三种统计方法都适用
