在巨人的肩膀前行 催化R包开发

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥到各个领域。让我们一起动起来吧,开始R的极客理想。

关于作者:

  • 张丹(Conan), 程序员Java,R,PHP,Javascript
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/r-package-faster/

r-devtools

前言

开发自己的R包sayHello 一文中,我们看到了如何从底层,按照R语言的标准构建一个R语言的扩展包。但实施过程确实复杂,会让很多的统计学工作者望而却步。如果能有一种比较简单方式,简化开发过程,那该多好啊!

我们是幸运的,Hadley Wickham(ggplot2,plyr的作者)已经帮我们梳理出了一套开发流程。站在巨人的肩膀上,看得更高,走得更远。

目录

  1. 开发流程介绍
  2. 编写功能代码
  3. 调试程序
  4. 单元测试
  5. 撰写文档
  6. 程序打包
  7. 程序发布

1. 开发流程介绍

站在巨人的肩膀,开发R包我们有3个武器:devtools, roxygen2, testthat

  • devtools:让开发变得简单,各种开发小工具的合集,非常实用。
  • roxygen2:通过注释的方式,生成文档,远离Latex的烦恼。
  • testthat:单元测试,让R包稳定、健壮,减少升级的痛苦。

标准化的开发流程:

  1. 编写功能代码
  2. 调试程序
  3. 单元测试
  4. 撰写文档
  5. 程序打包

2. 编写功能代码

1). 安装程序包:devtools, roxygen2, testthat


#依赖库
~ sudo apt-get install libcurl4-openssl-dev
~ sudo apt-get install libxml2-dev

#请使用root权限启动R
~ sudo R

> install.packages("devtools")
> install.packages("roxygen2")
> install.packages("testthat")

> library(devtools)
> library(roxygen2)
> library(testthat)

#查看
> search()
 [1] ".GlobalEnv"        "package:testthat"  "package:roxygen2"
 [4] "package:digest"    "package:stats"     "package:graphics"
 [7] "package:grDevices" "package:utils"     "package:datasets"
[10] "package:methods"   "Autoloads"         "package:base"

构建工程chinaWeather
创建骨架,代替package.skeleton()


> setwd("/home/conan/R")

> create("/home/conan/R/chinaWeather")
Creating package chinaWeather in /home/conan/R
No DESCRIPTION found. Creating default:

Package: chinaWeather
Title:
Description:
Version: 0.1
Authors@R: # getOptions('devtools.desc.author')
Depends: R (>= 3.0.1)
License: # getOptions('devtools.desc.license')
LazyData: true

> setwd("/home/conan/R/chinaWeather")
> dir()
[1] "DESCRIPTION" "man"         "R"

编辑DESCRIPTION文件

~ vi /home/conan/R/chinaWeather/DESCRIPTION
Package: chinaWeather
Type: Package
Title: a visualized package for china Weather
Description: a visualized package for china Weather
Author: Dan Zhang
Maintainer: Dan Zhang
Version: 0.1
Depends: R (>= 3.0.1)
License: GPL-2
LazyData: true
Date: 2013-08-05

增加函数文件chinaWeather.R


~ vi /home/conan/R/chinaWeather/R/chinaWeather.R

#define a filename from current date
filename<-function(date=Sys.time()){
  paste(format(date, "%Y%m%d"),".csv",sep="")
}

3. 调试程序

加载程序包到R中


> load_all("/home/conan/R/chinaWeather")
Loading chinaWeather

> filename
function(date=Sys.time()){
  paste(format(date, "%Y%m%d"),".csv",sep="")
}


> filename()
[1] "20130805.csv"

> day<-as.Date("20110701",format="%Y%m%d")
> filename(day)
[1] "20110701.csv"

4. 单元测试

编写单元测试代码


~ mkdir /home/conan/R/chinaWeather/inst/tests
~ vi /home/conan/R/chinaWeather/inst/tests/test.chinaWeather.R

library(testthat)
context("filename: current of date")

test_that("filename is current of date", {
  daystr<-paste(format(Sys.Date(), "%Y%m%d"),".csv",sep="")
  expect_that(filename(), equals(daystr))

  day<-as.Date("20110701",format="%Y%m%d")
  expect_that(filename(day), equals("20110701.csv"))
})

运行单元测试


#单个文件的单元测试
> source("/home/conan/R/chinaWeather/inst/tests/test.chinaWeather.R")
> test_file("/home/conan/R/chinaWeather/inst/tests/test.chinaWeather.R")
filename: current of date : ..

#对目录下所有文件的单元测试
> test_dir("/home/conan/R/chinaWeather/inst/tests/",reporter = "summary")
filename: current of date : ..

#自动单元测试
> src<-"/home/conan/R/chinaWeather/R/"
> test<-"/home/conan/R/chinaWeather/inst/tests/"
> auto_test(src,test)
filename: current of date : ..

#对package执行测试
> test("/home/conan/R/chinaWeather")
Testing chinaWeather
Loading chinaWeather
filename: current of date : ..

完成单元测试!下面开始撰写文档。

5. 撰写文档

这里撰写文档,使用源代码注释的方式,然后生成latex,再生成doc。比起原始的直接写latex要容易的多。

打开源代码文件:chinaWeather.R


~ vi /home/conan/R/chinaWeather/R/chinaWeather.R

#' Define a filename from current date.
#'
#' @param date input a date type
#' @return character a file name
#' @keywords filename 
#' @export
#' @examples
#' filename()
#' filename(as.Date("20110701",format="%Y%m%d"))
filename<-function(date=Sys.time()){
  paste(format(date, "%Y%m%d"),".csv",sep="")
}

生成latex文档


> library(roxygen2)
Loading required package: digest

> roxygenize("/home/conan/R/chinaWeather")
Updating collate directive in  /home/conan/R/chinaWeather/DESCRIPTION
Updating namespace directives
Writing chinaWeather.Rd
Writing filename.Rd

查看生成的latex文件


~ cat /home/conan/R/chinaWeather/man/filename.Rd

\name{filename}
\alias{filename}
\title{Define a filename from current date.}
\usage{
  filename(date = Sys.time())
}
\arguments{
  \item{date}{input a date type}
}
\value{
  character a file name
}
\description{
  Define a filename from current date.
}
\examples{
filename()
filename(as.Date("20110701",format="\%Y\%m\%d"))
}
\keyword{filename}

6. 程序打包

详细的打包解释,请参考:开发自己的R包sayHello

对上面程序过程,更简化操作可以用如下3条命令


> load_all("/home/conan/R/chinaWeather")
> test("/home/conan/R/chinaWeather")
> document("/home/conan/R/chinaWeather")

程序检查


> check("/home/conan/R/chinaWeather")
Updating chinaWeather documentation
Loading chinaWeather
'/usr/lib/R/bin/R' --vanilla CMD build '/home/conan/R/chinaWeather'  \
  --no-manual --no-resave-data

* checking for file '/home/conan/R/chinaWeather/DESCRIPTION' ... OK
* preparing 'chinaWeather':
* checking DESCRIPTION meta-information ... OK
* checking for LF line-endings in source and make files
* checking for empty or unneeded directories
* building 'chinaWeather_0.1.tar.gz'

'/usr/lib/R/bin/R' --vanilla CMD check  \
  '/tmp/RtmpM5NdJp/chinaWeather_0.1.tar.gz' --timings

* using log directory '/tmp/RtmpM5NdJp/chinaWeather.Rcheck'
* using R version 3.0.1 (2013-05-16)
* using platform: x86_64-pc-linux-gnu (64-bit)
* using session charset: ASCII
* checking for file 'chinaWeather/DESCRIPTION' ... OK
* checking extension type ... Package
* this is package 'chinaWeather' version '0.1'
* checking package namespace information ... OK
* checking package dependencies ... OK
* checking if this is a source package ... OK
* checking if there is a namespace ... OK
* checking for executable files ... OK
* checking for hidden files and directories ... OK
* checking for portable file names ... OK
* checking for sufficient/correct file permissions ... OK
* checking whether package 'chinaWeather' can be installed ... OK
* checking installed package size ... OK
* checking package directory ... OK
* checking DESCRIPTION meta-information ... OK
* checking top-level files ... OK
* checking for left-over files ... OK
* checking index information ... OK
* checking package subdirectories ... OK
* checking R files for non-ASCII characters ... OK
* checking R files for syntax errors ... OK
* checking whether the package can be loaded ... OK
* checking whether the package can be loaded with stated dependencies ... OK
* checking whether the package can be unloaded cleanly ... OK
* checking whether the namespace can be loaded with stated dependencies ... OK
* checking whether the namespace can be unloaded cleanly ... OK
* checking loading without being on the library search path ... OK
* checking for unstated dependencies in R code ... OK
* checking S3 generic/method consistency ... OK
* checking replacement functions ... OK
* checking foreign function calls ... OK
* checking R code for possible problems ... OK
* checking Rd files ... OK
* checking Rd metadata ... OK
* checking Rd cross-references ... OK
* checking for missing documentation entries ... OK
* checking for code/documentation mismatches ... OK
* checking Rd \usage sections ... OK
* checking Rd contents ... OK
* checking for unstated dependencies in examples ... OK
* checking examples ... OK
* checking PDF version of manual ... OK

Checking chinaWeather with devtools
Checking for any extra files in built .tar.gz file... OK

查检通过.
注:请安装

sudo apt-get install texlive-full

7. 程序发布

我们把写的程序发布到github上面,然后通过devtools,我可以方便的把程序从github下载安装。

在github创建一个新的资源库:chinaWeather
https://github.com/bsspirit/chinaWeather

提交本地代码到github


~ cd /home/conan/R/chinaWeather
~ git init
~ git add .
~ git commit -m 'init commit'
~ git remote add origin https://github.com/bsspirit/chinaWeather
~ git push -u origin master

To https://github.com/bsspirit/chinaWeather
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

通过devtools下载,并安装代码。
现在我的chinaWeather包,已经在github上面发布了,如果其他的同学想使用可以下面命令安装。


> library(devtools)
> install_github("chinaWeather","bsspirit")
Installing github repo(s) chinaWeather/master from bsspirit
Downloading chinaWeather.zip from https://github.com/bsspirit/chinaWeather/archive/master.zip
Installing package from /tmp/RtmpSaXYcA/chinaWeather.zip
Installing chinaWeather
'/usr/lib/R/bin/R' --vanilla CMD INSTALL  \
  '/tmp/RtmpSaXYcA/chinaWeather-master'  \
  --library='/home/conan/R/x86_64-pc-linux-gnu-library/3.0'  \
  --with-keep.source --install-tests

* installing *source* package 'chinaWeather' ...
** R
** inst
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
* DONE (chinaWeather)

#测试包
> library(chinaWeather)
> filename()
[1] "20130805.csv"

#查看文档
> ?filename
filename             package:chinaWeather              R Documentation
Define a filename from current date.
Description:
     Define a filename from current date.
Usage:
       filename(date = Sys.time())
Arguments:
    date: input a date type
Value:
     character a file name
Examples:
     filename()
     filename(as.Date("20110701",format="%Y%m%d"))

我们完成了,开发R包的全部流程。依赖于devtools, roxygen2, testthat三个包,真是事半功倍,比起完全手动操作提高效率了很多!!

希望更多的朋友,可以站在巨人的肩膀前行,创造让人惊叹的成果来!!

转载请注明出处:
http://blog.fens.me/r-package-faster/

打赏作者

This entry was posted in R语言实践

  • xiaofeng.0007

    您好,有些问题请教:1,为什么要传到github,然后又下载下来?2,除了这个流程还有没有更详细的资料呢?现在是知道怎么做,但是不知道为什么要这样做啊!谢谢!邮箱:xiaofeng.0007@gmail.com

    • 1. github可以方便的管理代码.

      2. 对于开发者来说,你要想发布自己的包,要放到CRAN上面,这是个慢长和复杂的过程。对于R的用户来说,可以直接从github下载你的包。简化了发布过程,你不觉得很方便么。

      3. 这个流程是目前我知道的最方便的流程了。如果提交到CRAN,代码规范,包结构, 都去google吧,都有答案的。

      • xiaofeng.0007

        谢谢,在linux上做了一遍,最后还是遇到个问题:为什么library后用不了?但是查看?filename却有结果呢?百思不得其解,check都没问题的,难道是build时有问题?

        • 你下载的是最新的版本吗?

          你这个问题,一般是NAMESPACE文件中,没有写export(filename)造成的。

          参考项目地址
          https://github.com/bsspirit/chinaWeather

          • xiaofeng.0007

            谢谢,一针见血啊,已经可以运行!不过又有新的问题了,再次麻烦你了:1,什么时候用S3method()?是因为默认的methods不行?对于methods概念比较模糊。2,useDynLib作用是载入共享对象?为什么么不可以用import()?3,最开始构建工程的时候为什么么用create(),这个相比于package.skeleton()好像没有什么优势啊?4,关于Hadley Wickham打包的文章一直没找到,能发个链接?

          • 1. S3和S4,建议自己构造的对象都用S4的。S3是遗留的问题。目前,这方面的介绍文章很少。

            有两个官方文档需要自己阅读:
            Writing R Extensions
            Building Packages in R

            2. useDynLib,主要用于加载其他语言的动态库。比如像rJava需要加载jri.dll(jri.so)

            3. devtools是为了简化R包开发流程的工具包。如果你用这个包,最好按照他规定的流程去开发。他规定的这个流程,我们没必要打破,再画轮造车。

            4. package.skeleton()仅仅是生成几个文件,没有对开发流程做任何的标准化。自己也可以创建这几个文件。完全没什么用。

            5. Hadley Wickham的文章,都出自devtools这个项目,我写的博客,大部分是基于自己的体会,没有任何翻译。
            https://github.com/hadley/devtools

          • xiaofeng.0007

            谢谢大神的耐心指导!真心感谢,谢谢!!希望在CRAN上能早日看到您的包!

          • 🙂

  • xiaofeng.0007

    没找到转载的按钮啊?怎么转载你这篇文章?

    • 没有转载按钮,如果转载就是复制+粘贴。

      • xiaofeng.0007

        嗯,好的,你的文章写得非常好,希望能够转载,不过复制+粘贴后排版有点问题!

  • xiaofeng.0007

    你好,如果R包依赖的不是其它R包,而是网络上的软件怎么办?是不是要configuration,还是只要在SystemRequirements说明就可以呢?

    • 这个情况,我不太清楚。

      你可参考一下谢益挥的animation包的实现写法。
      animation::saveGIF需要依赖于ImageMagick或者GraphicsMagick。

      • xiaofeng.0007

        谢大的包需要用户自行安装。我想自动安装的,昨天找到了个包也可以实现类似的功能。但是尝试了很久都不知道怎么自动加载那个依赖包,Depends和import都不行啊!

        • 自动安装,估计R语言很难实现吧,是不是对R语言要求太高了。

          • xiaofeng.0007

            这个应该是有的,要不然开发出来的R包有依赖关系的话,不就不能用了?我以前加载的包,可没有手动去下载那依赖包的!

          • xiaofeng.0007

            发现原因了,之前是我这边有点问题。只要在Depends中说明,install后library()就会自动加载依赖包。。

          • 依赖R包,在Depends配置好就行了。

            我以为你是想自动安装第三方软件呢,”网络上的软件”!

  • xiaofeng.0007

    之前在51cto上看到一篇报道:“2014最值得学习的语言—必须是R”。应该是您的杰作吧,写得很精辟!!让我对R充满信心啊!

  • xiaofeng.0007

    又来麻烦下你了,请部下:打包后有什么好方法进行调试吗?我是重新加载原代码来调试的,比较麻烦。可不可加载R包后,也可以进去调试呢?

    • 似乎没有什么其他方法,只能通过源代码的方式调试。

      • xiaofeng.0007

        好的,谢谢!晚安……

  • xiaofeng.0007

    在linux下怎么打包成zip格式?
    R CMD INSTALL –build test.tar.gz和R CMD build –binary test都不行啊???

    • 我不记得是否支持打包到zip,通用的是tar.gz;等我有时间时,再查一下。

      • xiaofeng.0007

        好的,谢了!

  • Pingback: 发布gridgame游戏包 | 粉丝日志()

  • Pingback: R语言性能可视化lineprof | 粉丝日志()

  • Pingback: R语言中的数学计算 | 粉丝日志()

  • xiaoxiao feng

    你好。如果要把用R做的模型打包怎么办呢?我现在是把模型保存成RData格式的文件,每次load一下这个文件,如果打包该怎么处理呢?谢谢

  • Pingback: R语言中文分词包jiebaR | 粉丝日志()