前言
今天来讨论下利用Tree-Based的方法来建立基因之间的调控关系,最近看到一篇17年发表在Nature Methods的文章《SCENIC: single-cell regulatory network inference and clustering》,其中有一个步骤是利用树模型来预测转录因子作用的靶基因,而这一步调用的是GENIE3来做预测的,所以这一次我们来看看GENIE3是如何进行工作的
附上GitHub地址:https://github.com/vahuynh/GENIE3/tree/master/GENIE3_R
步骤
首先我们先来看一下输入的数据长什么样子:
行名为不同的sample,而列名为基因名,表格可以理解为标准化后的表达量,接下来就可以上代码了:
# transpose expression matrix to (samples x genes)
#将普通的基因表达谱进行转换,sample为行名,基因为列名,
expr.matrix <- t(expr.matrix)
# setup weight matrix
num.samples <- dim(expr.matrix)[1]
num.genes <- dim(expr.matrix)[2]
gene.names <- colnames(expr.matrix)
weight.matrix <- matrix(0.0, nrow=num.genes, ncol=num.genes)
rownames(weight.matrix) <- gene.names
colnames(weight.matrix) <- gene.names
# get number of input genes, names of input genes
# 这里的input.gene.names指的是所有的基因
input.gene.names <- gene.names
# compute importances for every target gene
# 遍历每一个基因,target.gene.name是其中的一个基因
for (target.gene.idx in seq(from=1, to=num.genes)) {
target.gene.name <- gene.names[target.gene.idx]
# remove target gene from input genes
these.input.gene.names <- setdiff(input.gene.names, target.gene.name)
# 对遍历到的基因做差集,setdiff是差集的意思,these.input.gene.names则是除去target.gene.name以外的所有基因
num.input.genes <- length(these.input.gene.names)
# 以除去target.gene.name基因以外,剩下基因的表达量作为决策变量
x <- expr.matrix[,these.input.gene.names]
# target.gene.name基因的表达量作为响应变量
y <- expr.matrix[,target.gene.name]
# set mtry, mtry为特征值变量
mtry <- round(sqrt(num.input.genes))
# Normalize output
y <- y / sd(y)
# 随机森林回归建模
rf <- randomForest(x, y, mtry=mtry, ntree=1000, importance=FALSE)
im <- importance(rf)[,'IncNodePurity']
im.names <- names(im)
weight.matrix[im.names, target.gene.name] <- im
}
result = weight.matrix / num.samples
注意我们进行建模的变量的输入和输出:
# 以除去target.gene.name基因以外,剩下基因的表达量作为决策变量,有若干列表达数据
x <- expr.matrix[,these.input.gene.names]
# target.gene.name基因的表达量作为响应变量,为一列数据
y <- expr.matrix[,target.gene.name]
#建模
rf <- randomForest(x, y, mtry=mtry, ntree=1000, importance=FALSE)
其中,随机森林回归的决策变量是除去目标基因以外的所有基因表达矩阵,响应变量是该目标基因的表达向量。那么决策变量的列名(一串基因名)可以理解为回归的变量;而响应变量可以理解为在各个sample中,该基因的表达量
这里在randomForest中有一个比较重要的参数叫IncNodePurity,维基上给的解释是:
Mean Decrease Gini (IncNodePurity) - This is a measure of variable importance based on the Gini impurity index used for the calculating the splits in trees. The higher the value of mean decrease accuracy or mean decrease gini score, the higher the importance of the variable to our model.
是衡量在建树过程中,该变量作为判别回归变量对模型是否重要的指标(IncNodePurity)
事实上我们在建树的时候,将y当作响应变量,将x当作回归的决策变量,比方说第一个target.gene.name为TBX3,第一个指标为GATA5=0.13572435,那么GATA5表达值的改变会对TBX3的表达值的改变产生比较大的影响,在生物学上可以理解为这两个基因有互作,即改变GATA5的表达量,那么会对TBX3的表达量产生重要影响,可解释为这两个基因有互作,且是GATA5调控TBX3
最终的result为:
它反应了基因之间的权重关系,值得注意的是该矩阵并不是实对称矩阵,所以行基因为from gene,而列基因为to gene,比方说TBX3 -> GATA5 和 GATA5 -> TBX3的权重是不一样的,最终整理为:
那么接下来,根据权重阈值可以进行筛选,选出有互作的基因Candidates
小tip
(1). 随机森林回归的概念
其实真正区分回归还是分类问题的关键是响应变量的类型,若响应变量为数量型变量(数值型变量,连续型变量)则属于回归问题;若响应变量为是分类型变量(因子型变量,定性变量),则属于分类问题
我们简单介绍一些随机森林回归的大致原理:
由上面的代码为例子,
#以其中第一个基因为例子
target.gene.name <- gene.names[1]
# remove target gene from input genes
these.input.gene.names <- setdiff(input.gene.names, target.gene.name)
# 对遍历到的基因做差集,setdiff是差集的意思,these.input.gene.names则是除去target.gene.name以外的所有基因
num.input.genes <- length(these.input.gene.names)
# 以除去target.gene.name基因以外,剩下基因的表达量作为决策变量
x <- expr.matrix[,these.input.gene.names]
# target.gene.name基因的表达量作为响应变量
y <- expr.matrix[,target.gene.name]
# set mtry, mtry为特征值变量
mtry <- round(sqrt(num.input.genes))
# Normalize output
y <- y / sd(y)
# 随机森林回归建模
rf <- randomForest(x, y, mtry=mtry, ntree=1000, importance=FALSE)
im <- importance(rf)[,'IncNodePurity']
im.names <- names(im)
建模的数据类型如下图所示,随机森林回归的本质是若干个树回归
假设我们拥有D = { (x1,y1), (x2,y2), ..., (xn,yn) },i 代表上面数据框的每一行; xi 是一个 m 维的向量,即 xi 含有 m 个 features
那么树回归是将数据 D 里面的元素按照决策变量的条件由父节点分散到子节点,假设一共有 N 个叶子,每个叶子分得一定量的数据,而最终的结果显示在终子节点(没有往下分叉的节点为终子节点)上
注意:这里的决策变量的条件指的是按照每一个决策变量的取值范围(以GATA5为例,小于 0.05 的为一类,介于 0.05 到 0.1的为一类,大于 0.1 的又为一类,其他决策变量以此类推),那么按照决策变量的条件筛选出的 yi 将会被分配到不同的节点里面,理论上按照不同的决策变量筛选的 yi 值应该会具有相同的特征,即它们的值( yi )相差不会太大
那么接下来根据决策变量的条件将 D 里面的数据平均分配给这些节点,每个节点拟合一个值(比方说平均值),最终要求:
即每一个节点分得若干个数据,用每个节点的平均值代替每个节点的特征值,那么每个终子节点里面的数据与该终子节点的均值MSE最小,则达到我们的要求
每个模型里面的均方差达到最小,那么这个回归树才算合格,而随机森林回归则是由若干个回归树组成,选择最优的那一个
最后我们不妨用模型预测一下:
predict = predict(rf,x)
貌似还是有些差别的。。。
(2). IncNodePurity的概念
根据前面所叙述的那样,IncNodePurity是基于基尼系数计算的值,而基尼系数越大,代表分出的类不确定性较大,分类效果不好。(IncNodePurity代表基尼系数的下降)
“IncNodePurity”即increase in node purity,值越大表示该变量的重要性越大。
IncNodePurity的大小是衡量某一个回归变量对随机森林回归模型贡献的一个指标,数值越大,贡献越大,反之越小
varImpPlot(rf,main = "The importance")
上图描述的就是各个回归变量对模型的贡献
当然,lncMSE是衡量回归变量重要性的一种指标,lncMSE越高,该变量越重要,反之越不重要
lncMSE即Increase in MSE(%)值,更高的MSE%值意味着更重要的变量
除此之外还有几个衡量分类指标重要性的因素:Mean Decrease Accuracy 和 Mean Decrease Gini 为随机森林模型中的两个重要指标。其中,mean decrease accuracy 表示随机森林预测准确性的降低程度,该值越大表示该变量的重要性越大;mean decrease gini 计算每个变量对分类树每个节点上观测值的异质性的影响,从而比较变量的重要性。该值越大表示该变量的重要性越大