1. 理论
rrBLUP是基因组选择最常用的模型之一,也是间接法模型的代表。回顾一下,所谓间接法是指:在参考群中估计标记效应,再结合预测群的基因型信息将标记效应累加,最终获得预测群的个体估计育种值。而直接法则是指:将个体作为随机效应,参考群体和预测群体遗传信息构建的亲缘关系矩阵作为方差协方差矩阵,通过迭代法估计方差组分,进而求解混合模型获取待预测个体的估计育种值。简言之,直接法是通过构建A/G/H等矩阵求解育种值,间接法是通过计算标记效应来获得育种值。
RRBLUP全称“ridge regression best linear unbiased prediction”,即岭回归最佳线性无偏预测。光从长串名字看,里面涉及到大量的统计学基本概念,可分为两部分看。一是Ridge Regression,岭回归是一种改良的最小二乘估计法,专用于解决共线性数据分析的有偏估计回归方法,通过在损失函数中加上一个正则化项,放弃最小二乘法的无偏性,以损失部分信息、降低精度为代价获得回归系数更符合实际;二是BLUP,对一个随机效应(如个体育种值)的预测具有线性(预测量是样本观察值的线性函数)、无偏(预测量的数学期望等于随机效应本身的数学期望)和预测误差方差最小等统计学性质。
最佳线性无偏预测( best linear unbiased prediction,BLUP)是线性模型中用来评估随机效应的,等同于固定效应中的最佳线性无偏估计(best linear unbiased estimates, BLUE)。
- best:估计误差最小,估计与真实育种值相关最大;
- linear:估计基于线性模型,假设个体性能是遗传和非遗传效应的总和;
- unbiased:估计过程中估计值是无偏的,估计与真实育种值间平均差为零,即所有可能估计值的平均值等于真实育种值;
- prediction:一个体将来作为亲本的预测育种值。
越解释越混乱,这些基础知识需要好好巩固巩固。
先看间接法的模型公式:
- y为表型向量;
- X为固定效应系数矩阵,其长度为训练群个体数目,元素值均为1的向量;
- b为固定效应,即为训练群表型均值;
- Zi为第i个位点数字化基因型向量(如:{0,1,2}或{-1,0,1}之类的编码,不同编码方式有无差异?但rrBLUP必须为{-1,0,1}编码方式),之和即为标记编码关联矩阵;
- gi为第i个位点效应值,需要根据模型估计出的分子标记效应向量;
- e为残余误差,服从分布N~(0, Iσe2)。
关键在于求解标记效应:
- σgi2为第i个标记方差,直接与性状遗传构建相关。
间接法重难点在于如何对参数的先验分布(即对gi及其方差服从的分布)进行合理的假设。RRBLUP模型假设所有标记都具有效应,且来源于同一个分布,即σgi2相等(理论上RRBLUP与GBLUP方法是等价的)。但实际上所有标记不会都具有效应,标记方差也会不同,因而出现了各种假设的Bayes方法,这样就带来更多待估参数,提高准确性的同时也增加了计算量。
2. 实操
采用rrBLUP Package 来进行实操学习。
2.1 rrBLUP包简介
rrBLUP包主要两个函数:
A.mat
函数用来过滤和填充基因型。
A.mat(
X, #编码为{-1,0,1}的标记矩阵,可包含小数点(表明已填充过)和NA
min.MAF=NULL, #最小等位基因频率
max.missing=NULL, #最大缺失值比例
impute.method="mean", #填充方法,mean/EM
tol=0.02, #EM算法的收敛标准
n.core=1, #EM算法的并行核心数(仅unix)
shrink=FALSE, #收缩估计
return.imputed=FALSE #返回填充标记矩阵
)
返回加性效应关系矩阵(即kinship),填充后的分子标记矩阵。
mixed.solve
函数直接求解模型参数。
mixed.solve(
y, #观测值
Z=NULL, #随机效应矩阵
K=NULL, #随机效应协变量矩阵
X=NULL, #固定效应矩阵
method="REML", #最大似然估计方法,ML/REML
bounds=c(1e-09, 1e+09), #岭回归参数两元素边界
SE=FALSE, #是否计算标准误
return.Hinv=FALSE #是否H取逆,一般在GWAS中用,忽略之
)
mixed.solve
函数返回值(列表):
- Vu:σ^2_u的估计值
- Ve:σ^2_e的估计值
- beta:BLUE(β),即训练群表型均值
- u:BLUP(u),即预测值
- LL:maximized log-likelihood(ML/REML值)
如果设了标准误参数,则会返回:
- beta.SE:β标准误
- u.SE:u^*-u
2.2 实操
- 导入表型和基因型数据
#load in the sample files
library(rrBLUP)
#load the Markers and Phenotypes
Markers <- as.matrix(read.table(file="snp.txt"), header=F)
dim(Markers)
Markers[1:10,1:10]
Pheno <-as.matrix(read.table(file ="traits.txt", header=TRUE))
dim(Pheno)
head(Pheno)
- 过滤和填充
#####
#what if markers are NA?
#impute with A.mat
#remove markers with more than 50% missing data
impute=A.mat(Markers,max.missing=0.5,impute.method="mean",return.imputed=T)
#均值填充导致标记不止0,-1,1三类数
Markers_impute2=impute$imputed
dim(Markers)
dim(Markers_impute2)
- 数据划分训练集和验证集
#######
#define the training and test populations
#training-60% validation-40%
train= as.matrix(sample(1:96, 58))
test<-setdiff(1:96,train)
Pheno_train=Pheno[train,]
m_train=Markers_impute2[train,]
Pheno_valid=Pheno[test,]
m_valid=Markers_impute2[test,]
- 预测和验证
以产量性状为例,其他一样,可写循环。
########
yield=(Pheno_train[,1])
yield_answer<-mixed.solve(yield, Z=m_train, K=NULL, SE = FALSE, return.Hinv=FALSE)
# yield_answer<-mixed.solve(yield, Z=m_train, K=NULL, SE = TRUE, return.Hinv=FALSE)
YLD = yield_answer$u
e = as.matrix(YLD)
pred_yield_valid = m_valid %*% e
pred_yield=(pred_yield_valid[,1])+yield_answer$beta
pred_yield
yield_valid = Pheno_valid[,1]
YLD_accuracy <-cor(pred_yield_valid, yield_valid, use="complete" )
YLD_accuracy
- 循环n次
#### cross validation for many cycles for yield only
traits=1
cycles=500
accuracy = matrix(nrow=cycles, ncol=traits)
for(r in 1:cycles){
train= as.matrix(sample(1:96, 58))
test<-setdiff(1:96,train)
Pheno_train=Pheno[train,]
m_train=Markers_impute2[train,]
Pheno_valid=Pheno[test,]
m_valid=Markers_impute2[test,]
yield=(Pheno_train[,1])
yield_answer<-mixed.solve(yield, Z=m_train, K=NULL, SE = FALSE, return.Hinv=FALSE)
YLD = yield_answer$u
e = as.matrix(YLD)
pred_yield_valid = m_valid %*% e
pred_yield=(pred_yield_valid[,1])+yield_answer$beta
pred_yield
yield_valid = Pheno_valid[,1]
accuracy[r,1] <-cor(pred_yield_valid, yield_valid, use="complete" )
}
mean(accuracy)
3. 补充说明
关于模型
需要提前清洗数据,并编码基因型数据。
关于交叉验证
rrBLUP预测准确性与训练群和验证群大小、标记数目以及遗传力等有关。可以看到,上面循环500次的重复性并不是很好。
使用K折交叉验证的方法可能会好些。关于交叉验证,一般有三种方法:
- 简单交叉验证:就是上面的方法,随机将样本分为一定比例的训练集和测试集,然后训练和验证模型,再把样本打乱,重新选择训练集和测试集,继续训练数据和验证模型。一般用于初步模型的建立。
- K折交叉验证:先将数据集随机划分为K个大小相近的互斥子集,每次随机选择K-1份作为训练集,剩下一份做测试集。当这一轮完成后,下一轮重新随机选择K-1份来训练数据,最后多轮结果取均值。交叉验证法评估结果的稳定性和保真性在很大程度上取决于K的取值。
- 留一交叉验证:是K折交叉验证的特例,即K等于样本数N。每次N-1样本训练,留一个样本验证。一般用于样本量很少的情况(如小于50)。
- booststrapping自助法也算是一种比较特殊的交叉验证法:在m个样本中随机采一个样放入训练集,再将样本放回,重复采集m次得到m个样本组成的训练集(可能有重复样本),同时用原始的m个样本做测试集。一般用于样本量非常少的情况(如小于20)。