学习连接:bigmemory
第一个例子
我们先放一个官网的例子:
cpp
#include
// The next line is all it takes to find the bigmemory
// headers -- thanks to the magic of Rcpp attributes,
// and as bigmemory now accesses Boost headers from the BH package,
// we need to make sure we do so as well in this Rcpp::depends comment.
//
// Boost headers can generate some warning with the default compilation
// options for R. To suppress these, we can enable C++11 mode which gets
// us 'long long' types.
//
// If your compiler is to old, just disable / remove the following line
// [[Rcpp::plugins(cpp11)]]
// Ensure R uses the headers for Boost (a dependency) and bigmemory
//
// [[Rcpp::depends(BH, bigmemory)]]
#include
#include
using namespace Rcpp;
// Logic for BigColSums.
// template 的目的是接受所有的数据类型(char,short,int,double),而不需要依次定义
template
NumericVector BigColSums(XPtr pMat, MatrixAccessor mat) {
// Create the vector we'll store the column sums in.
// 定义列求和的数据类型为数值型向量,这个数值型向量里面包括三个列的和,NumericVector
NumericVector colSums(pMat->ncol());
// 对列进行遍历求和
for (size_t i=0; i < pMat->ncol(); ++i)
## std::accumulate 的作用是对向量内的元素累计求和
colSums[i] = std::accumulate(mat[i], mat[i]+pMat->nrow(), 0.0);
## 返回一个数值型向量
return colSums;
}
// Dispatch function for BigColSums
//
// [[Rcpp::export]]
NumericVector BigColSums(SEXP pBigMat) {
// First we have to tell Rcpp what class to use for big.matrix objects.
// This object stores the attributes of the big.matrix object passed to it
// by R.
XPtr xpMat(pBigMat);
// To access values in the big.matrix, we need to create a MatrixAccessor
// object of the appropriate type. Note that in every case we are still
// returning a NumericVector: this is because big.matrix objects only store
// numeric values in R, even if their type is set to 'char'. The types
// simply correspond to the number of bytes used for each element.
switch(xpMat->matrix_type()) {
// 一共有四种数据类型,char,short,int,double
case 1:
// MatrixAccessor(*xpMat) 定义一个和 *xpMat 一样的矩阵
return BigColSums(xpMat, MatrixAccessor(*xpMat));
case 2:
return BigColSums(xpMat, MatrixAccessor(*xpMat));
case 4:
return BigColSums(xpMat, MatrixAccessor(*xpMat));
case 8:
return BigColSums(xpMat, MatrixAccessor(*xpMat));
default:
// This case should never be encountered unless the implementation of
// big.matrix changes, but is necessary to implement shut up compiler
// warnings.
throw Rcpp::exception("unknown type detected for big.matrix object!");
}
}
其中 :
- NumericVector BigColSums(SEXP pBigMat),它的作用是判断输入的数据类型,First we have to tell Rcpp what class to use for big.matrix objects;一共有四种数据类型,char,short,int,double
- std::accumulate 对列进行遍历求和
MatrixAccessor
定义一个内容和 xpMat 一样的矩阵(*xpMat)
R codes
suppressMessages(require(bigmemory))
# set up big.matrix
nrows <- 10000
bkFile <- "bigmat.bk"
descFile <- "bigmatk.desc"
bigmat <- filebacked.big.matrix(nrow=nrows, ncol=3, type="double",
backingfile=bkFile, backingpath="C:/cpp/",
descriptorfile=descFile,
dimnames=c(NULL,NULL))
# Each column value with be the column number multiplied by
# samples from a standard normal distribution.
set.seed(123)
# 随机生成三列的矩阵
for (i in 1:3){
bigmat[,i] = rnorm(nrows)*i
}
# 查看矩阵
bigmat[,]
[,1] [,2] [,3]
[1,] -5.604756e-01 4.7414504410 -2.508890221
[2,] -2.301775e-01 -0.3336239141 -0.661718979
[3,] 1.558708e+00 1.8539227907 -6.310544302
[4,] 7.050839e-02 -1.1363034955 -5.003422629
[5,] 1.292877e-01 0.4501801612 -3.293888574
# Call the Rcpp function
# 利用 Rcpp 编译 cpp 文件
Rcpp::sourceCpp('C:/cpp/mean.cpp')
## bigmat@address 推测是存放的待计算的矩阵
## R函数 BigColSums 要与 cpp 中的函数名 BigColSums 相同
res <- BigColSums(bigmat@address)
print(res)
其中 :
- backingfile 为缓存文件,
- bigmatk.desc 为备份文件
- backingpath 为保存上述两个文件的路径
- bigmat@address 推测是存放的待计算的矩阵
- bigmat[,] 为查看矩阵的命令
第二个例子
关于计算亲缘关系矩阵的例子,这个例子源于GWAS的数据
理论:
参考《亲缘关系矩阵------G矩阵》
假设存在基因型矩阵M,M矩阵是一个n×m矩阵,n表示个体数,m表示位点数。有3个二倍体个体,4个SNP位点。对于每个位点,小写等位基因表示其出现频率最低。把基因型矩阵转换为基因含量矩阵,具体参数用基因型中最小频率等位基因的个数表示,即0、1、2。0表示Major frequent(大写字母)的纯合子,2表示Minor frequent(小写字母)的纯合子,1表示杂合子
因此矩阵可改写为:
## snp1 snp2 snp3 snp4
## Ind1 0 1 0 1
## Ind2 0 1 1 0
## Ind3 2 0 0 0
为了便于计算,通常会将M矩阵减1,每个位点等位基因含量变为-1、0、1三种形式。减1的目的也是为了将每列的均值标准化为0。如果三种等位基因型出现的频率是相同的,那么-1后,每列的均值就是0
## snp1 snp2 snp3 snp4
## Ind1 -1 0 -1 0
## Ind2 -1 0 0 -1
## Ind3 1 -1 -1 -1
构建P矩阵:
其中i表示位点编号,pi表示每个位点最小等位基因频率。P矩阵中反应的是每个snp位点(每列)两个等位基因频率偏离均值0.5的程度。以snp1,最小等位基因为t,频率为p=2/6=0.333333
构建Z矩阵:
Z <- M - P
## snp1 snp2 snp3 snp4
## Ind1 -0.6666667 0.3333333 -0.3333333 0.6666667
## Ind2 -0.6666667 0.3333333 0.6666667 -0.3333333
## Ind3 1.3333333 -0.6666667 -0.3333333 -0.3333333
计算G矩阵:
在geno中计算的Rcodes:
M = t(geno[,])-1
p_lower <- (apply(M,2,sum)+nrow(M))/(nrow(M)*2)
p_upper <- 2*(p_lower-0.5)
p_matrix <- matrix(p_upper,byrow=T,nrow=nrow(M),ncol=ncol(M))
P <- p_matrix
Z <- M - P
d <- 2*sum(p_lower*(1 - p_lower))
G <- Z %*% t(Z) / d
G
Rcpp代码:
其中:
- geno代表基因型数据,0表示Major frequent(大写字母)的纯合子,2表示Minor frequent(小写字母)的纯合子,1表示杂合子,Major frequent(大写字母)代表出现频率高的碱基,Minor frequent(小写字母)代表出现频率低的碱基;geno的列代表样品;geno的行代表100个位点
- pho代表表型数据,V2列为样品名,V6列为表型值
# 表型数据,V2列为样品名。V6列为表型值
phe
V2 V6
1 33-16 101.50
2 38-11 102.70
3 4226 101.20
4 4722 105.50
5 A188 108.10
6 A214N 95.13
7 A239 100.20
8 A272 103.40
9 A441-5 93.82
10 A554 91.43
# 基因型数据,0表示Major frequent(大写字母)的纯合子,2表示Minor frequent(小写字母)的纯合子,1表示杂合子,Major frequent(大写字母)代表出现频率高的碱基
geno[,]
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 0 0 0 0 2 0 2 2 0 0
[2,] 2 0 2 0 2 2 2 2 2 0
[3,] 2 2 2 2 2 0 0 0 2 0
[4,] 0 0 0 0 0 2 0 0 0 0
[5,] 0 0 0 0 0 0 2 2 0 2
[6,] 0 0 0 0 0 2 2 2 0 0
[7,] 2 0 0 1 0 0 0 2 0 0
[8,] 0 0 0 0 0 0 0 0 0 0
[9,] 0 0 0 0 0 0 0 0 0 0
[10,] 2 0 2 0 0 0 0 0 0 0
[11,] 2 0 0 0 0 2 0 0 2 2
[12,] 0 0 0 2 0 0 0 0 0 2
[13,] 0 2 0 0 0 0 0 0 0 0
Rcpp::sourceCpp('C:/cpp/kinship.cpp')
# 基因型数据计算亲缘关系
K <- kin_cal_m(geno@address, threads = 1)
K
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1.94173093 -0.453299057 0.61782348 -0.221936590 -0.02485004 -0.35047129 -0.6889460 -0.33333333
[2,] -0.45329906 1.993144816 -0.27763496 -0.003427592 -0.49185947 0.55355613 -0.1276778 0.05655527
[3,] 0.61782348 -0.277634961 2.25021422 -0.303341902 -0.19194516 -0.51756641 -0.4275921 -0.84318766
[4,] -0.22193659 -0.003427592 -0.30334190 1.384747215 -0.08911740 -0.58611825 -0.1105398 -0.14053128
[5,] -0.02485004 -0.491859469 -0.19194516 -0.089117395 1.82176521 -0.38903171 -0.2133676 -0.37189374
[6,] -0.35047129 0.553556127 -0.51756641 -0.586118252 -0.38903171 2.19880034 -0.1962296 -0.01199657
[7,] -0.68894602 -0.127677806 -0.42759212 -0.110539846 -0.21336761 -0.19622965 1.9502999 0.24935733
[8,] -0.33333333 0.056555270 -0.84318766 -0.140531277 -0.37189374 -0.01199657 0.2493573 2.06169666
[9,] 0.01799486 -0.791773779 0.02227935 0.125107112 -0.02056555 -0.68894602 -0.2562125 -0.50042845
[10,] -0.50471294 -0.457583548 -0.32904884 -0.054841474 -0.02913453 -0.01199657 -0.1790917 -0.16623822
[,9] [,10]
[1,] 0.01799486 -0.50471294
[2,] -0.79177378 -0.45758355
[3,] 0.02227935 -0.32904884
[4,] 0.12510711 -0.05484147
[5,] -0.02056555 -0.02913453
[6,] -0.68894602 -0.01199657
[7,] -0.25621251 -0.17909169
[8,] -0.50042845 -0.16623822
[9,] 2.25021422 -0.15766924
[10,] -0.15766924 1.89031705
其中
- K 代表亲缘关系矩阵,每一列代表一个个体亲缘关系的特征向量
- bigm 代表基因型矩阵,与 geno 矩阵一样
#define ARMA_64BIT_WORD 1
#include
#include
#include
#include
#include
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::depends(bigmemory, BH)]]
using namespace std;
using namespace Rcpp;
using namespace arma;
// 求矩阵的每一行平均值
template
arma::vec BigRowMean(XPtr pMat, int threads = 0){
//创造一个矩阵对象 bigm ,其中 bigm 内容与输入的 pMat 矩阵一样
MatrixAccessor bigm = MatrixAccessor(*pMat);
int ind = pMat->ncol();
int j, k, m = pMat->nrow();
double p1 = 0.0;
arma::vec mean(m);
#pragma omp parallel for private(p1, k)
for (j = 0; j < m; j++){
p1 = 0.0;
for(k = 0; k < ind; k++){
// bigMatrix 前列后行 [k] 为列,[j] 为行
p1 += bigm[k][j];
}
mean[j] = p1 / ind;
}
return mean;
}
arma::vec BigRowMean(SEXP pBigMat, int threads = 0){
XPtr xpMat(pBigMat);
switch(xpMat->matrix_type()) {
case 1:
return BigRowMean(xpMat, threads);
case 2:
return BigRowMean(xpMat, threads);
case 4:
return BigRowMean(xpMat, threads);
case 8:
return BigRowMean(xpMat, threads);
default:
throw Rcpp::exception("unknown type detected for big.matrix object!");
}
}
template
SEXP kin_cal_m(XPtr pMat, int threads = 0){
MatrixAccessor bigm = MatrixAccessor(*pMat);
int n = pMat->ncol();
int m = pMat->nrow();
int i = 0, j = 0, k = 0;
// Mean 向量表示的是基因型 bigm 矩阵每一行的均值,即每个 loci 的基因频率
arma::vec Mean = BigRowMean(pMat, threads);
// 求 (0.5 * Mean) % (1 - 0.5 * Mean) 元素之和,% 在这里指代向量对应元素相乘
double SUM = sum((0.5 * Mean) % (1 - 0.5 * Mean));
// 定义一个行列都为 n 的 kin 矩阵
arma::mat kin(n, n);
arma::vec coli(m);
arma::vec colj(m);
#pragma omp parallel for schedule(dynamic) firstprivate(coli, colj) private(i, j, k)
for(i = 0; i < n; i++){
for(k = 0; k < m; k++){
// 对基因型 bigm 矩阵每一行元素分别减去这一行的平均值
// coli[k] 表征基因型 bigm 矩阵的每一行减去对应行均值之后的行向量
coli[k] = bigm[i][k] - Mean[k];
}
for(j = i; j < n; j++){
for(k = 0; k < m; k++){
// 对基因型 bigm 矩阵每一行元素分别减去这一行的平均值
// colj[k] 表征基因型 bigm 矩阵的每一行减去对应行均值之后的行向量
colj[k] = bigm[j][k] - Mean[k];
}
// coli % colj 代表两个向量对应元素相乘,类似于 Z 矩阵的运算,即 ZZ'
kin(i, j) = kin(j, i) = 0.5 * sum(coli % colj) / SUM;
}
}
return Rcpp::wrap(kin);
}
// [[Rcpp::export]]
SEXP kin_cal_m(SEXP pBigMat, int threads = 0){
XPtr xpMat(pBigMat);
switch(xpMat->matrix_type()){
case 1:
return kin_cal_m(xpMat, threads);
case 2:
return kin_cal_m(xpMat, threads);
case 4:
return kin_cal_m(xpMat, threads);
case 8:
return kin_cal_m(xpMat, threads);
default:
throw Rcpp::exception("unknown type detected for big.matrix object!");
}
}
其中:
- 以
SEXP
为首定义的函数和以return Rcpp::wrap();
作为的返回值,SEXP 的作用是将cpp的返回值转换为R的SEXP返回值,一般cpp函数返回值返回到R对象,都需要定义 SEXP 的函数名,返回值为return Rcpp::wrap();
括号内填返回对象XPtr
是bigmemory中定义矩阵数据类型的语法pMat MatrixAccessor
代表创建一个内容与 pMat 相同的矩阵 bigmbigm = MatrixAccessor (*pMat); return Rcpp::wrap(kin);
返回R的数据类型SEXP- bigMatrix 的原则是前列后行, [k] 为列,[j] 为行
- 如果是向量运算符%在这里指代向量的对应元素相乘,如果是元素,则代表元素之间则表示取余数运算;即如果运算的对象是两个向量,那么 % 代表两个向量的对应元素相乘,如果运算的对象是两个元素,那么 % 代表两个元素的对应元素取余数的运算
第三个例子
理论部分:
GWAS分析本质上是回归分析:
y 为表型值,X为基因型矩阵,b 为效应值。因此按照多元回归分析求解系数的方法求解效应值 b:
在实际的求解中 X 矩阵不仅包括遗传信息,还包括 kinship,因此 X 矩阵的构成为:
我们将 snp 引起的差异定义为我们所关注的因素,而由 kinship 引起的差异定义为 随机因素,上述 C1,C2,Ck 分别代表 kinship 的特征向量 ,snp 代表某一个 snp 在若干个体中的遗传差异;b1,b2,bk 分别代表 kinship 所带来的效应,c 代表 snp 带来的真正遗传上的效应
在求解的过程中,效应值 b可以如下计算:
作者在这里采取了分块矩阵的方法进行计算,设:
那么:
其中:
补充分块矩阵求逆公式:
因此,效应值 b计算为:
因此计算的核心为计算分块矩阵 M-1 中的 M11,M12,M21 和 M22
核心代码分析:
1. 计算亲缘关系矩阵的特征矩阵
# step 1 计算亲缘关系矩阵
K <- MVP.K.VanRaden(
M = geno,
priority = priority,
cpu = 1,
verbose = verbose
)
# step 2 对亲缘关系矩阵 K 进行特征值分解,并选择前 nPC 个特征值
eigenK <- eigen(K, symmetric = TRUE)
ipca <- eigenK$vectors[, 1:nPC]
## CV.GLM 为前 nPC 特征值矩阵
CV.GLM <- ipca[,1:nPC.GLM, drop = FALSE]
其中:
- 函数 MVP.K.VanRaden() 即为第二个例子中的 VanRaden 法计算亲缘关系的方法,其输入矩阵 geno 为:
- K 为亲缘矩阵,
,描述的是 10 个个体之间相互的亲缘关系
- CV.GLM 矩阵 为亲缘关系的特征值矩阵,取了前 5 个特征向量,
2. 求解GWAS的glm回归分析
kinship矩阵对应的特征矩阵 (CV.GLM 矩阵),也可以称之为固定效应矩阵**
# step 1 利用 GLM 计算效应值
### 1. phe为表型值矩阵
### 2. geno为基因型矩阵
### 3. CV.GLM 为亲缘关系矩阵的特征矩阵
glm.results <- MVP.GLM(phe=phe, geno=geno, CV=CV.GLM, cpu=1, verbose = verbose)
colnames(glm.results) <- c("Effect", "SE", paste(colnames(phe)[2],"GLM",sep="."))
z = glm.results[, 1]/glm.results[, 2]
lambda = median(z^2, na.rm=TRUE)/qchisq(1/2, df = 1,lower.tail=FALSE)
## 函数MVP.GLM()
MVP.GLM <- function(phe,geno,CV=NULL,cpu=1,verbose=TRUE){
n <- ncol(geno)
m <- nrow(geno)
ys <- as.numeric(as.matrix(phe[,2]))
if(is.null(CV)){
X0 <- matrix(1, n)
}else{
CV.index <- apply(CV, 2, function(x) length(table(x)) > 1)
CV <- CV[, CV.index, drop=FALSE]
X0 <- cbind(matrix(1, n), CV)
}
# 亲缘关系特征矩阵第一列合并一个全为 1 的列??
X0 <- as.matrix(X0)
## crossprod(X0) 求矩阵 X0 的内积
## MASS::ginv 求解矩阵的广义逆矩阵
iX0X0 <- MASS::ginv(crossprod(X0))
Rcpp::sourceCpp('C:/Users/lenovo/Downloads/extdata/cpp/glm_c.cpp')
results <- glm_c(y = ys, X = X0, iXX = iX0X0, geno@address, verbose = verbose, threads = cpu)
return(results[, c(1, 2, ncol(results))])
}
其中:
- pho 矩阵为:
,表征为 10 个个体的表型值
- X0 矩阵代表亲缘关系的特征矩阵,理论部分对应 ω
- iX0X0 为 X0X0 (ω'ω) 的逆矩阵,理论部分对应 (ω'ω)-1
#define ARMA_64BIT_WORD 1
#include
#include "mvp_omp.h"
#include
#include
#include
#include
#include
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::depends(bigmemory, BH)]]
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::depends(RcppProgress)]]
using namespace std;
using namespace Rcpp;
using namespace arma;
template
SEXP glm_c(const arma::vec &y, const arma::mat &X, const arma::mat & iXX, XPtr pMat, const bool verbose = true, const int threads = 0){
omp_setup(threads);
// 定义 genomat 矩阵,内容和基因型矩阵 pMat 相同
MatrixAccessor genomat = MatrixAccessor(*pMat);
// y 代表个体表型值向量,X 代表kinship矩阵对应的特征矩阵,或者也可以称之为固定效应矩阵
//iXX 为 X 矩阵的广义逆矩阵,pMat 为基因型矩阵
// 获得基因型矩阵的列数
int ind = pMat->ncol();
// 获得基因型矩阵的行数
int mkr = pMat->nrow();
// 获得kinship矩阵对应特征矩阵 X 的列数,或者也可以将 X 矩阵称之为固定效应矩阵
int q0 = X.n_cols;
// 获得表型数据向量的长度
int y_len = y.n_elem;
if(y_len != ind)
throw Rcpp::exception("number of individuals not match.!");
// xy 矩阵代表
arma::mat xy = X.t() * y;
double yy = sum(y % y);
// 创建一个行为 mkr(mkr 为基因型矩阵的行数),列为 1 + 1 + 1 + q0(q0 为 kinship矩阵对应特征矩阵的列数) 且元素值为 0 的矩阵 res
arma::mat res(mkr, 1 + 1 + 1 + q0);
// 创建一个长度为 ind(与基因型矩阵行数相等) 且元素值为 0 的向量 snp
arma::vec snp(ind);
// 创建一个行数,列数均为 q0 + 1 (q0 为 kinship矩阵对应特征矩阵的列数) 且元素值为 0 的矩阵 iXXs
arma::mat iXXs(q0 + 1, q0 + 1);
#pragma omp parallel for schedule(dynamic) firstprivate(snp, iXXs)
//对每一个snp进行遍历
for(int i = 0; i < mkr; i++){
// ind 为基因型矩阵的列数,genomat[ii][i] 前列后行
for(int ii = 0; ii < ind; ii++){
// snp 代表基因型矩阵的每一个行向量,即同一个 snp 在不同个体中的形式
snp[ii] = genomat[ii][i];
}
double sy = sum(snp % y);
//计算 ss ,即 x'x
double ss = sum(snp % snp);
//计算 t2 ,即 x'ω(ω'ω)^-1*ω'x
arma::mat xs = X.t() * snp;
arma::mat B21 = xs.t() * iXX;
double t2 = as_scalar(B21 * xs);
double B22 = (ss - t2);
double invB22;
int df;
// 计算 invB22,即 M22
if(B22 < 1e-8){
invB22 = 0;
df = ind - q0;
}else{
invB22 = 1 / B22;
df = ind - q0 - 1;
}
// 计算 M12 矩阵
arma::mat NeginvB22B21 = -1 * invB22 * B21;
// 计算 M22 矩阵
iXXs(q0, q0)=invB22;
// span的功能是取子矩阵,规则是前行后列
// 计算 M11 矩阵
iXXs.submat(0, 0, q0 - 1, q0 - 1) = iXX + invB22 * B21.t() * B21;
// 计算 M12 矩阵
iXXs(q0, span(0, q0 - 1)) = NeginvB22B21;
// 计算 M21 矩阵
iXXs(span(0, q0 - 1), q0) = NeginvB22B21.t();
// statistics
// 计算 ω'y
arma::mat rhs(xy.n_rows + 1, 1);
// 计算 snp*y
rhs.rows(0, xy.n_rows - 1) = xy;
rhs(xy.n_rows, 0) = sy;
// 计算效应值 b
arma::mat beta = iXXs * rhs;
// 显著性计算
double ve = (yy - as_scalar(beta.t() * rhs)) / df;
arma::vec se(q0 + 1);
arma::vec pvalue(q0 + 1);
for(int ff = 0; ff < (q0 + 1); ff++){
se[ff] = sqrt(iXXs(ff, ff) * ve);
pvalue[ff] = 2 * R::pt(abs(beta[ff] / se[ff]), df, false, false);
res(i, ff + 2) = pvalue[ff];
}
if(invB22 == 0){
beta[q0] = NA_REAL;
se[q0] = NA_REAL;
res(i, q0) = NA_REAL;
}
// beta[q0] 为 snp 的效应值
res(i, 0) = beta[q0];
res(i, 1) = se[q0];
}
return wrap(res);
}
// [[Rcpp::export]]
SEXP glm_c(const arma::vec & y, const arma::mat & X, const arma::mat & iXX, SEXP pBigMat, const bool verbose = true, const int threads = 0){
XPtr xpMat(pBigMat);
switch(xpMat->matrix_type()){
case 1:
return glm_c(y, X, iXX, xpMat, verbose, threads);
case 2:
return glm_c(y, X, iXX, xpMat, verbose, threads);
case 4:
return glm_c(y, X, iXX, xpMat, verbose, threads);
case 8:
return glm_c(y, X, iXX, xpMat, verbose, threads);
default:
throw Rcpp::exception("unknown type detected for big.matrix object!");
}
}
本例子的 Ck,k=6
- X 矩阵:
,第一列向量全为 1, 输入的 X 矩阵:为上图的 C1,C2,.....,Ck所代表的内容,即亲缘关系特征值矩阵- xy 矩阵:
xy = X.t() * y
代表kinship特征矩阵所带来的效应- invB22:,1/B22 为 M22,即
iXX + invB22 * B21.t() * B21
计算的是 M11矩阵iXX 为 (ω'ω)-1;invB22 为 (x'x - x'ω(ω'ω)-1ω'x)-1;B21.t() 为 x'ω(ω'ω)-1;B21 = (ω'ω)-1ω'xarma::mat NeginvB22B21 = -1 * invB22 * B21
:计算的是 M12 矩阵B21 = (ω'ω)-1ω'x;invB22 为 (x'x - x'ω(ω'ω)-1ω'x)-1NeginvB22B21.t()
计算M21矩阵- rhs 矩阵为:
前六个元素为最后一个元素为
rhs 一共有7个元素,前6个对应C1,C2,.....,C6;最后一个为snp的效应- iXXs 矩阵 代表
,最后一行和最后一列代表snp效应:也就是 M-1 矩阵- beta向量:
arma::mat beta = iXXs * rhs
最后一个值为snp的效应值 -1.7054e+00
因此,只需要计算每一个 snp 对应的 beta[q0] 的值,即为 snp 的效应值
总结
这里有一份Rcpp不错的介绍:Rbook
Rcpp中的数据类型有:
1.IntegerVector: 整数向量;
2.NumercicVector: 数值向量;
3.LogicalVector: 逻辑向量;
4.CharacterVector: 字符型向量;
5.GenericVector: 列表;
6.ExpressionVector: 表达式向量;
7.RawVector: 元素为raw类型的向量。
8.IntergerMatrix, NumericMatrix: 整数值或数值矩阵。