欢迎大家学习一门新的课程,在这一门课程中,我们会学习到如何开发一个R语言包,学习完这门课程之后,同学们可以自己属于自己的R包,从一个R用户开始转变成为一个R语言开发者。
在R中,可以分享代码的基本单位是包。包把代码,数据,文档和测试整合在一起,这样可以很容易的和别人分享。截止到目前,R包的公共发布网站CRAN,已经有了6000多个包可以使用。正是这么多的资源,使得R语言如此的成功,每当我们遇到一个问题,往往已经有人解决了你的问题,你则可以通过下载他们的包从他们的工作中受益。
本课程的目的是教会同学们如何开发包,让同学们写出自己的包,而不只是使用别人的包。我们为什么要开发包:首先是与他们分享,做成包他人也可以很方便的使用。其次,做成包可以很方便自己的使用,节省自己的时间。
首先,确保安装了了最新版的R(至少是3.1.2以上),然后需要安装以下的包:
install.packages('c("devtools","roxygen2","testthat","knitr")')
其次,确保Rstudio 是最新版的
命名有三个正式的要求:
名称只能包含字母,数字,和点号(.)
必须以一个字母开始
不能以点号结束
这意味着名字不能使用下划线或者横杠,并且建议不要使用点号,因为其有令人混淆的含义,比如文件扩展名字或者S3方法
对于起名字还是有一些好的建议的:
选择一个比较容易被搜索到的名字,这让潜在的用户能够找到你的包
避免同时使用大写和小写,这样会难以输入并且难以记住
找到一个与这个问题相关的词,修改他比如:knitr [knitr + r]
使用缩略词 :Rcpp = R+c++(plus plus)
在单词后面加上一个r:stringr
一旦我们确定了包的结构,就可以创建包,使用Rstudio:
File->New Project
选择 New Directory
选择 R Package
最后,对包进行命名,然后点击Create Project 进行创建
使用包的第一个原则,就是包中的所有的R语言代码都要放到R/目录当中,本节,我们会学习到一些关于R/目录的知识,有关在文件中组织函数的建议,以及形成良好的代码风格的提示
在文件中编写函数的时候,有两种极端的做法不是很好:把所有的函数都放在一个文件中,以及把每个函数都发在不同的文件,一般而言,文件名要包含函数的功能,并且文件名字要有意义并且以.R结尾
一个好的文件名: fit_model.R
这样我们就能知道这个文件是做什么事情的
对象的名称
变量名称和函数名称应该小写,使用下划线进行分割,一般情况下,变量名应该是名词,函数名应该是动词
好的名字:day_one
到目前为止,大家可能已经在编写R脚本,通过source()来加载文件运行R代码。脚本中的代码和R包中的代码有两个主要的区别:
脚本中,代码在加载的时候运行,代码在编译的时候运行(下载好这个号的时候),这就意味着包的代码应该只包含对象,对象的绝大部分能容应该是函数
包的函数会被使用到任何环境,因此需要小心处理包与调者的关系
当使用source 加载脚本的时候,每一行代码都会被执行,执行的结果可以立即使用。对于包而言,有一点不一样,加载过程分为两步,包编译的时候,目录下的所有代码都会被执行,结果会保存下来。使用library 的时候,这些保存的结果就可以用了。
举个例子:x = Sys.time()
如果放在一个脚本里面,x显示的是脚本什么时候被source运行的。如果放在包中,则会告诉你什么包什么时候被编译的。
这就是说不应该在包里面直接运行代码:包只能创建对象,主要是函数。举一个例子:
我们有一个包叫做test,包含的代码如下:
library(ggplot2)
show_mtcars = function(){
qplot(mpg,wt,data=mtcars)
}
然后我们加载test包,运行函数:
library(foo)
show_mtcars()
因为,ggplot2的qplot函数将不可用:library(test)的时候不会重新执行library(ggplot2),因此需要改成这个样子:
show_mtcars = function(){
library(ggplot2)
qplot(mpg,wt,data = mtcars)
}
脚本和包的一个巨大的区别是:别人会使用你的包,并在一个你从未想到的环境中使用,这意味着你需要注意R的运行环境。如果使用library()加载的一个包,或者使用options()修改了一个全局变量,那么你就已经修改了R的运行环境,这样会造成R的代码非常难以理解,因此最好不要做以下事情:
DESCRIPTION 的作用是储存包中重要的元数据,每一个包都必须有一个DESCRIPTION,他看起来是这个样子的:
Package: test
Type: Package
Title: What the Package Does (Title Case)
Version: 0.1.0
Author: Who wrote it
Maintainer: The package maintainer <yourself@somewhere.net>
Description: More about what it does (maybe more than one line)
Use four spaces when indenting paragraphs within the Description.
License: What license is it under?
Encoding: UTF-8
LazyData: true
描述文件需要列出这个包所有的依赖包,以下几行代码表示需要依赖dplyr和ggvis:
Imports:
dplyr,
ggvis
下面几行说明,可以使用ggvis和dplyr,但是并不是必须的:
Suggests:
dplyr,
ggvis
在DESCRIPTION中添加Imports和Suggests 很简单的方法是使用
devtools::user_package()
这样会自动的把需要得到写入DESCROPTION文件中正确的位置,例如:
devtools::use_package("dplyr")
ggplot2 的Title和Description如下:
Title: Create Elegant Data Visualisations Using the Grammar of Graphics
Description: A system for 'declaratively' creating graphics,
based on "The Grammar of Graphics". You provide the data, tell 'ggplot2'
how to map variables to aesthetics, what graphical primitives to use,
and it takes care of the details.
我们还需要指定作者是谁,因为这样使用者知道如果包有什么问题可以联系谁。下面是添加作者的一个例子:
Authors@R:person('Hadley','Wickham',email = '...',role = c('aut','cre))
这一条命令再说,包的作者(aut)和维护者(cre)都是Hadley Wickham,他的邮件是什么。 person有四个主要的参数:
如果计划发布包,许可证是非常重要的,如果不打算发布,可以忽略这个部分。 对于R包,需要考虑三种许可证:
发布的版本包括三个数字: <主版本号>.<此版本号>.<补丁版本>
文档是包最重要的一部分。通过文档,用户才知道如何使用这个包,如何使用 这个包的某一个函数。通过?来访问某一函数的文档举例子:
?mean
制作文档一般有基本的四个步骤
我们会一步一步介绍,首先是在源文件添加注释:roxygen注释从#开始,区别于一般的注释.下面是一个简单的函数文档,这个文件名为add.R:
#'Add together two number
#'
#' @param x A number
#' @param y A number
#' @return The sum of \code{x} and 、code{y}
#' @example
#' add(1,1)
#' add(10,1)
add <- function(x,y){
x+y
}
然后运行:
devtools::document()
在man的目录下会出现一个文件add.Rd,看起来如下:
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/add.R
\name{add}
\alias{add}
\title{Add together two number}
\usage{
add(x, y)
}
\arguments{
\item{x}{A number}
\item{y}{A number}
}
\value{
The sum of \code{x} and code{y}
}
\description{
Add together two number
}
此时可以访问这个函数的帮助文档:?add
roxygen 的注释以#’开始,第一句是文档的标题,第二段是描述,写在文档的最前面,简要说明函数的功能,第三段以及以后的段落是细节描述
@seealso 用于添加其他指向其他有用资源
@family 用于添加一族的相关函数
@keywords 用于添加关键词
@param 用于添加函数参数
@examples 用于添加例子
@return 用途田间返回值描述
包文档,是一个页面对于这个包的描述,通过packages?包名来访问它。因为没有一个包的对象,所以需要为NULL提供文档.这里提供一个包文档的例子:
#‘ test :A package for test
#'
#' The test packages provides some functions :
#'
#' @section test Functions:
#' The foo function ...
#'
#' @docType package
#' @name test
NULL
其他的文档还包括类,范型和方法的文档,这里就不详细介绍
为什么要使用Github
其让我们可以非常容易的分享包,任何用户只需要使用两行代码就可以安装包:
install.packages('devtools')
devtools::install_github('username/packagename')
在Rstudio中选择Git/SVN,点击Create RSA Key
5.把你的SSH共钥上传给GitHub:https://github.com.settings/ssh。找到秘钥最简单的方法是在Rstudio中Git/SVN偏好中点击“View public key”(也可以不操作这一步)
git init
重启Rstudio,再次打开Rstudio,就会出现Git一栏:
首先,在Github创建新的仓库,它的名称和包的名称一样,然后点击提交
打开shell,输入提交操作:
git init
git add .
git commit -m 'first commit'
git remote add origin https://github.com/liamamilin/Fibonacci.git
git push -u origin master
意思是告诉Git你的本地仓库有一个GitHub的远程版本,第二行是将目前的工作推送到那个远程仓库
这样,其他人可以通过:
install.packages('devtools')
devtools::install_github('username/packagename')
来安装你写的包了
写一个函数计算斐波那契数列,并封装成为一个包,上传到Github.
斐波那契数列的代码如下:
Fibonacci = function(n){
if (x ==1 || x == 2){
return(1)
}else{
return(Fibonacci(x-1) + Fibonacci(x-2))
}
}
本课程还有很多内容没有提到,如需要参考更多的内容,可以查看: