使用C++製做一個R包

以前介紹瞭如何製做併發布本身的R語言包。這篇文章介紹怎麼製做一個C++的R包,也就是使用Rcpp製做R包。html

其實製做Rcpp的R包和普通的R包製做仍是有區別的。本人也嘗試按照以前的作法,在R腳本里面使用cppFunction()寫一個C++腳本,以腳本運行的時候很完美,沒有出現任何錯誤,可是當構建成包時,安裝以後每次運行都出現錯誤。因此不得不嘗試其餘方法建立Rcpp的R包。git

一、爲何要用Rcpp

Rcpp其實是R語言調用C++的一個接口,而C++在運行速度上要比R語言快成百上千倍!!好比有以下兩個數據:github

> aa
  pos
1   2
2   4
3   6
> bb
  start end
1     1   3
2     5   8
3     7  10

其中aa$pos表示一段DNA序列的SNP位點,bb表示該DNA序列上的基因位置(包括基因起始位置和終止位置),若是你要判斷aa中全部的SNP是否在基因上,咱們一般的作法是寫兩個for循環,用aa中的每個SNP位點去判斷bb中的每個基因。也就是要有3 * 3 = 9次運算。可是當數據量足夠大的時候,假若有幾十萬SNP位點,有幾萬基因序列,那麼這個循環可能要執行成百上千萬次!這對R語言來講,運行時間會以小時來計了。
而C++能夠在一兩分鐘內完成!
參考:如何提高備受詬病的R的運行速度markdown

二、構建RcppR包過程

(1)準備工做

和以前的介紹同樣,仍是要安裝並加載devtools 和 roxygen2兩個工具包。
而後建立一個路徑(「~/Documents/CheckOverlap),在此路徑內構建R包併發

library(devtools)
library(roxygen2)
setwd("~/Documents/")
create("CheckOverlap")
setwd("./CheckOverlap/")
devtools::use_rcpp() #會自動生成一些相關文件

和以前的文件結構不一樣,這時會出現一個src文件夾。
(2)寫C++函數
按照你的目的參考以下格式寫C++函數,並將該文件保存成「~/Documents/CheckOverlap/src/CheckPointRange.cpp「。
若是是在Rstudio中,能夠「新建」 —「C++文件「,這樣會自動生成一個模版。ssh

// CheckPointRange.cpp
#include <Rcpp.h>
using namespace Rcpp;

//'@title Check if points in segments
//'@description
//'To check if a number in a range. 
//'Return a vector of 0,1 if the the number 
//'in a range(1) or not (0).
//'@param pos a vector of numbers of points
//'@param start a vector of numbers of starting position
//'@param end a vector of numbers of ending position
//'@examples
//'aa <- c(2,4,6)
//'bb1 <- c(1,5,7)
//'bb2 <- c(3,8,10)
//'CheckPoint(aa,bb1,bb2)
//'@useDynLib CheckOverlap
//'@import Rcpp
//'@export
// [[Rcpp::export]]
IntegerVector CheckPoint(IntegerVector pos, IntegerVector start, IntegerVector end){
  int pos_size=pos.size();
  int seg_size=start.size();
  IntegerVector ismask(pos_size);
  for (int i=0; i<pos_size; i++) {
    for (int j=0; j<seg_size; j++){
      if ( pos[i]>=start[j] && pos[i]<=end[j] ){
        ismask[i]=1;
        break;
      }
    }
  }
  return ismask;
}

#include <Rcpp.h>
using namespace Rcpp;
//'@title Check if segments contain point
//'@description
//'To check if a range contains points. 
//'Return a vector of 0,1 
//'with 1 = contain points, 0 = not contain points.
//'@param pos a vector of numbers of points
//'@param start a vector of numbers of starting position
//'@param end a vector of numbers of ending position
//'@examples
//'aa <- c(2,4,6)
//'bb1 <- c(1,5,7)
//'bb2 <- c(3,8,10)
//'CheckRange(aa,bb1,bb2)
//'@useDynLib CheckOverlap
//'@import Rcpp
//'@export
// [[Rcpp::export]]
IntegerVector CheckRange(IntegerVector pos, IntegerVector start, IntegerVector end){
  int pos_size=pos.size();
  int seg_size=start.size();
  IntegerVector ismask1(pos_size);
  for (int i=0; i<seg_size; i++) {
    for (int j=0; j<pos_size; j++){
      if ( pos[j]>=start[i] && pos[j]<=end[i] ){
        ismask1[i]=1;
        break;
      }
    }
  }
  return ismask1;
}

注意,這兒寫了兩個函數,一個是用來判斷SNP是夠在基因上(CheckPoint),另外一個用來判斷基因上是否含有SNP位點(CheckRange)。
其中不少關鍵字是不可缺乏的,好比include, using, useDynLib 你的包名, import, export, [[Rcpp::export]]等。
而後ide

Rcpp::sourceCpp("./src/CheckPointRange.cpp")

或者在Rstudio點擊「Source「函數

(3)建包

setwd("~/Documents/CheckOverlap/")
document()

這個時候去檢查CheckOverlap文件夾,會有不少自動生成的文件,包括NAMESPACE、DESCRIPTION,在src子文件夾中,有.so, .o等文件名後綴的的文件。
在R子文件夾中,出現了一個RcppExports.R的文件,這個文件就至關於該包的主文件。
下面檢查包,看看是否存在錯誤。工具

setwd("..")
devtools::check("CheckOverlap")

(4)本地安裝並調試

setwd("~/Documents/")
install("CheckOverlap")
aa <- c(2,4,6)
bb1 <- c(1,5,7)
bb2 <- c(3,8,10)
CheckOverlap::CheckPoint(aa,bb1,bb2)
CheckOverlap::CheckRange(aa,bb1,bb2)

輸出結果爲spa

[1] 1 0 1
# 即SNP2和6位於基因上
[1] 1 1 0
# 即基因片斷1-3和5-8含有SNP位點。

至此,R包的構建已經完成

三、R包``發佈
設置GitHub帳戶,參考:
https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/
https://help.github.com/articles/adding-a-new-ssh-key-to-your-github-account/
在本身的GitHub帳戶上建立一個目錄,用來存放你要發佈的R包。

使用C++製做一個R包

在本地terminal中:

cd ~/Documents/CheckOverlap/
git init
git add *
git commit -m "first version"
git remote add wyg git@github.com:Yiguan/CheckOverlap.git
git push -u wyg master

建立,發佈;所有完成!
一個須要幾個小時完成的任務,如今只須要一兩分鐘就能夠完成!

======= THE END =======

參考資料:

https://www.r-bloggers.com/rcpp-and-roxygen2/

http://r-pkgs.had.co.nz/src.html

http://www.deanbodenham.com/learn/make-an-r-package-using-rcpp.html

使用C++製做一個R包

相關文章
相關標籤/搜索