Rcpp 与 bigmemory

学习连接: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!");
    }
}

其中 :

  1. NumericVector BigColSums(SEXP pBigMat),它的作用是判断输入的数据类型,First we have to tell Rcpp what class to use for big.matrix objects;一共有四种数据类型,char,short,int,double
  2. std::accumulate 对列进行遍历求和
  3. 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)

其中 :

  1. backingfile 为缓存文件,
  2. bigmatk.desc 为备份文件
  3. backingpath 为保存上述两个文件的路径
  4. bigmat@address 推测是存放的待计算的矩阵
  5. 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代码:

其中:

  1. geno代表基因型数据,0表示Major frequent(大写字母)的纯合子,2表示Minor frequent(小写字母)的纯合子,1表示杂合子,Major frequent(大写字母)代表出现频率高的碱基,Minor frequent(小写字母)代表出现频率低的碱基;geno的列代表样品;geno的行代表100个位点
  2. 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

其中

  1. K 代表亲缘关系矩阵,每一列代表一个个体亲缘关系的特征向量
  2. 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!");
    }
}

其中:

  1. SEXP为首定义的函数和以return Rcpp::wrap();作为的返回值,SEXP 的作用是将cpp的返回值转换为R的SEXP返回值,一般cpp函数返回值返回到R对象,都需要定义 SEXP 的函数名,返回值为return Rcpp::wrap(); 括号内填返回对象
  2. XPtr pMat 是bigmemory中定义矩阵数据类型的语法
  3. MatrixAccessor bigm = MatrixAccessor(*pMat); 代表创建一个内容与 pMat 相同的矩阵 bigm
  4. return Rcpp::wrap(kin); 返回R的数据类型SEXP
  5. bigMatrix 的原则是前列后行, [k] 为列,[j] 为行
  6. 如果是向量运算符%在这里指代向量的对应元素相乘,如果是元素,则代表元素之间则表示取余数运算;即如果运算的对象是两个向量,那么 % 代表两个向量的对应元素相乘,如果运算的对象是两个元素,那么 % 代表两个元素的对应元素取余数的运算

第三个例子

理论部分:

GWAS分析本质上是回归分析:



y 为表型值,X为基因型矩阵,b 为效应值。因此按照多元回归分析求解系数的方法求解效应值 b:


在实际的求解中 X 矩阵不仅包括遗传信息,还包括 kinship,因此 X 矩阵的构成为:


我们将 snp 引起的差异定义为我们所关注的因素,而由 kinship 引起的差异定义为 随机因素,上述 C1,C2,Ck 分别代表 kinship 的特征向量 ,snp 代表某一个 snp 在若干个体中的遗传差异;b1,b2,bk 分别代表 kinship 所带来的效应,c 代表 snp 带来的真正遗传上的效应

在求解的过程中,效应值 b可以如下计算:

image.png

作者在这里采取了分块矩阵的方法进行计算,设:


那么:



其中:

补充分块矩阵求逆公式:


因此,效应值 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]
  

其中:

  1. 函数 MVP.K.VanRaden() 即为第二个例子中的 VanRaden 法计算亲缘关系的方法,其输入矩阵 geno 为:
  2. K 为亲缘矩阵,

    ,描述的是 10 个个体之间相互的亲缘关系

  3. 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))])
}

其中:

  1. pho 矩阵为:

    ,表征为 10 个个体的表型值

  2. X0 矩阵代表亲缘关系的特征矩阵,理论部分对应 ω
  3. iX0X0X0X0 (ω'ω) 的逆矩阵,理论部分对应 (ω'ω)-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

  1. X 矩阵
    ,第一列向量全为 1, 输入的 X 矩阵:为上图的 C1,C2,.....,Ck所代表的内容,即亲缘关系特征值矩阵
  2. xy 矩阵xy = X.t() * y
    代表kinship特征矩阵所带来的效应
  3. invB22:1/B22 为 M22,即
  4. iXX + invB22 * B21.t() * B21计算的是 M11矩阵
    iXX 为 (ω'ω)-1invB22 为 (x'x - x'ω(ω'ω)-1ω'x)-1B21.t() 为 x'ω(ω'ω)-1B21 = (ω'ω)-1ω'x
  5. arma::mat NeginvB22B21 = -1 * invB22 * B21:计算的是 M12 矩阵
    B21 = (ω'ω)-1ω'xinvB22 为 (x'x - x'ω(ω'ω)-1ω'x)-1
  6. NeginvB22B21.t() 计算M21矩阵
  7. rhs 矩阵为:
    前六个元素为
    最后一个元素为

    rhs 一共有7个元素,前6个对应C1,C2,.....,C6;最后一个为snp的效应
  8. iXXs 矩阵 代表
    ,最后一行和最后一列代表snp效应:
    也就是 M-1 矩阵
  9. 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: 整数值或数值矩阵。

你可能感兴趣的:(Rcpp 与 bigmemory)