R · R 包开发
如需视频讲解,请移步:一只小蛮要
【要知道 · R】R包开发|保姆级教程
一般在初始阶段我们都是使用别人的函数来完成大部分任务,那些函数大多来自 R 标准安装的包或者可以从 CRAN 下载的包。
安装新的包可以拓展 R 的功能。比如说,安装 ggplot2 包提供了可视化数据的方法。R 中很多强大的功能都来自开发者贡献的包。
什么是包
技术上,包只不过是一套函数、文档和数据的合集,以一种标准的格式保存。包让我们能以一种定义良好的完整文档化方式来组织我们的函数,而且便于我们将程序分享给他人。
为什么要开发包
- 让一套常用函数及其使用说明文档更加容易取用。
- 创造一个能解决重要分析问题(比如数据可视化)的程序(一套相关函数)。
- 传世之作,福泽天下!
- 方便自己!
- ……
包可以直接分享,或者通过如 CRAN 和 GitHub 的在线软件库分享。R 包开发与 Git/GitHub 结合使用更佳。
开发必备工具
- RStudio
- usethis 包 —— 有超多的工具函数。
- devtools 包 —— 通过提供简化常见任务的R函数来简化包的开发。
- roxygen2 包 —— 再也不用为复杂的注释而头疼,可以一边写函数,一边写注释,将精力集中到写代码中,最后运行
devtools::document()
命令,就可以直接将所有注释写入 R 的说明文档。
准备就绪后,我们可以使用命令devtools::has_devel()
来进行检查。运行这行命令,返回“Your system is ready to build packages! ”
表示一切准备就绪,可以开始啦!
# 安装并加载开发包所需包
install.packages("usethis", "devtools", "roxygen2")
library(usethis)
library(devtools)
library(roxygen2)
# 检查
has_devel()
Your system is ready to build packages!
开发 R 包
1 命名规则
R包的命名主要有以下几个规则:
- 必须以字母开头(大写或小写),如:ggplot2,不能写成 2ggplot
- 只能包含字母(大写或小写),数字和点,如:covid19.analytics
- 不能和已有的包名称冲突,已有的包指 CRAN 和 bioconductor 上的包
CRAN 上已有的包可以在
https://cran.r-project.org/web/packages/available_packages_by_name.html 中查找;
bioconductor 上已有的包可以在
https://bioconductor.org/packages/release/BiocViews.html#___Software 中查找。
也可以使用命令available.packages()
查看 CRAN 上的包,bioManager::available()
来查看 bioconductor 上已有的包。
在创建R包前,不仅需要确保自己的包名是有效的,而且还有起一个好名字。好名字的特点包括:
- 和功能相关:比如做稳健 cox 回归的包叫做 coxrobust
- 易记:包的名字不宜全部使用小写字母,可以使用驼峰式如 MaN,或 aBa,或者可以加入点,如 gg.gap
- 注意版权:比如说 TCGA 是知名网站的名字,那么 R 包的名字应尽量避免重复,可以加入 r,如 rTCGA。
- 不宜太长:很多人会把包的名字起的过长,在 CRAN 和 bioconductor 上,大部分R包的名字在 4 到 9 个字符之间,6 个字符最佳,过长的包名拼写起来十分困难,无疑增加了使用的难度。
2 开发 R 包
首先,我们使用命令dir.create()
在d盘下新建文件夹 mypkg,并使用命令setwd()
设置工作目录至 mypkg 文件夹下,之后创建的所有R包都将会在这个目录中。
dir.create("d:/Desktop/OneDrive-shanghaitech.edu.cn/RStudio/mypkg")
setwd("d:/Desktop/OneDrive-shanghaitech.edu.cn/RStudio/mypkg")
接着使用 usethis 包中的create_package()
函数来创建R包,usethis 包会随着 devtools 包的安装而安装,随着 devtools 包的调用而调用。
usethis::create_package("xmypkg")
v Creating 'xmypkg/'
v Setting active project to 'D:/Desktop/OneDrive-shanghaitech.edu.cn/RStudio/mypkg/xmypkg'
v Creating 'R/'
v Writing 'DESCRIPTION'
Package: xmypkg
Title: What the Package Does (One Line, Title Case)
Version: 0.0.0.9000
Authors@R (parsed):
* First Last <[email protected]> [aut, cre] (YOUR-ORCID-ID)
Description: What the package does (one paragraph).
License: `use_mit_license()`, `use_gpl3_license()` or friends to
pick a license
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.0
v Writing 'NAMESPACE'
v Writing 'xmypkg.Rproj'
v Adding '^xmypkg\\.Rproj$' to '.Rbuildignore'
v Adding '.Rproj.user' to '.gitignore'
v Adding '^\\.Rproj\\.user$' to '.Rbuildigno**re'
v Opening 'D:/Desktop/OneDrive-shanghaitech.edu.cn/RStudio/mypkg/xmypkg/' in new RStudio session
v Setting active project to '<no active project>'**
create_package('xmypkg')
命令在 mypkg 文件夹下创建了 xmypkg 文件夹,这个就是我们的 R 包了,并且自动打开了一个新的界面:xmypkg.Rproj,可以直接关闭它。xmypkg 文件夹(也就是 xmypkg 包)默认创建了以下几个文件:
-
R文件夹:存放R代码文件夹,重要
- R包的心脏(我们写的所有函数都在此处)
- 里面的文件都是R脚本,也就是扩展名为.R的文件
- 每个文件包含什么嘞
- 一个函数
- 一个函数和它的辅助函数
- 一个函数家族
-
.gitignore文件:存放git信息的文件,会被忽略
-
.Rbuildignore文件:顾名思义就是build包时会忽略的文件,会被忽略
-
DESCRIPTION文件:R包的说明文档,重要
- 包含包的描述信息
- 人类和机器都能读取的格式
- 会展示在CRAN
- 是包的灵魂
- 一个有格式的文本文件(DFC:Debian control format)
- 每行由字段名称、冒号和后面的值组成
- 包含包的描述信息
-
xmypkg.Rproj文件:RStudio的项目文件,我们以后编辑R包的时候,都是通过打开它来编辑的,因为这个文件包含了创建R包的菜单,重要
-
NAMESPACE文件:存放R包函数命名空间的文件,不需要手动编辑,极其重要
- 一个文本文件,无需手动编辑
- 一个 list
- 一行一个
- 通常由 Roxygen2 完成
-
R包中的其他文件夹
R包中可以包含很多文件夹,不同的文件功能不同,常用的除了上面提到的R文件夹,还有data文件夹和vignette文件夹。
- R文件夹是存放R脚本的地方,也就是我们所有的R代码
- data文件夹不像R文件夹会自动产生,你可以使用函数
use_data()
来添加R数据,也可以手动新建 - vignette文件夹是用来添加markdown格式的说明文档,可以使用函数
use_vignette()
来创建,需要注意的是,如果你要添加vignette文件夹,需要安装knitr包、rmarkdowan包和pandoc。前两者的安装可以使用命令install.packages()
来安装即可,pandoc的安装参考它的网站https://pandoc.org/installing.html
-
R包文件夹的小缺陷
R包内的文件夹不支持二级目录,也就是R文件夹下不能再有下一级目录,这个也是R包的缺陷,因为如果函数过多,打理起来会比较麻烦。
3 封装 R 包
到现在为止,我们创建了一个空包,名字叫 xmypkg。接下来,为了对 R 包的制作过程有更直观的认识,我们对其直接进行封装。
封装R包主要有2个步骤:写入注释和建包。 有 3 种实现方式:菜单、命令和快捷键。
3.1 打开项目文件
上面我们介绍了R包内的常用文件,有一个特别重要的项目文件 xmypkg.Rproj,现在我们打开它。
和 RStudio 平常的界面不同,在菜单栏多了可下拉的 Build 菜单项,这里包含了封装 R 包常用的能。
3.2 通过菜单封装包
3.2.1 写入注释
首先是写入注释,在 Build 菜单下,单击 Document 项。
在 Build 窗口中,我们可以看到:更新文档,载入 xmypkg 包,最后完成更新。
3.2.2 建包
写好注释后,就是建包了,使用 Build 菜单下的 Install and Restart 或者 Clean and Rebuild
均可,选择任意一个单击即可,这里我们选择 Install and Restart。
选择 Install and Restart 之后,在 build 窗口,就可以看到:xmypkg 包被安装到 library 文件夹下,最后提示 Done (xmypkg) 表示安装成功。在 R 的控制台中,我们可以看到已经使用library()
命令调用了 xmypkg 包,xmypkg 已经可以使用了。
3.3 通过快捷键封装包
使用快捷键封装包超简单!
- 写入注释:Ctrl/Command + Shift + D,D —— document
- 建包:Ctrl/Command + Shift + B,B —— build
3.4 通过命令封装包
不论是快捷键还是菜单,本质上都是调用 devtools 包中的document()
函数和build()
函数。
学会使用命令封装非常重要,因为有一些信息仅在使用命令的时候才会给出。
- 写入注释:
devtools::document()
- 建包:
devtools::build()
使用命令封装包后的信息,不会再 Build 窗口中显示,而是在控制台中显示。
# 写入注释
devtools::document()
i Updating xmypkg documentation
i Loading xmypkg
# 建包
devtools::build()
√ checking for file 'D:\Desktop\OneDrive - shanghaitech.edu.cn\RStudio\mypkg\xmypkg/DESCRIPTION' ...
- preparing 'xmypkg':
√ checking DESCRIPTION meta-information ...
- checking for LF line-endings in source and make files and shell scripts
- checking for empty or unneeded directories
Removed empty directory 'xmypkg/man'
- building 'xmypkg_0.0.0.9000.tar.gz'
[1] "D:/Desktop/OneDrive - shanghaitech.edu.cn/RStudio/mypkg/xmypkg_0.0.0.9000.tar.gz"
3.5 调用 R 包
封装完R包后,我们就可以使用library()
命令来调用我们的包啦!
没有任何报错信息,说明 xmypkg 包制作成功。
在 Package 窗口中,也可以找到我们的 xmypkg 包。
现在我们已经学会如何创建、封装R包了,但是 xmypkg 还只是个空包,没有任何内容,不过一般在封装包之前,大家肯定就已经把函数搞定啦,所以这里就不讲解创建函数的过程了,让我们直接进入函数注释部分!
4 函数注释
roxygen2 !!!!!
4.1 插入注释框架
双击打开我们的项目文件 xmypkg.Rproj。
首先,我们写1个标准函数,并将它保存在R文件夹下,文件名为XXX.R,R语言代码文件的扩展名必须是R,而文件名不一定要和函数名一样,可以是XXXO.R,也可以是XX.R,但不能是中文。
# eg.
add <- function(x, y){
x + y
}
插入注释框架主要有2种方法:菜单插入、快捷键插入,不管哪一种,都要先将光标定位在函数内部,只有在函数内部,RStudio才能识别这是1个函数。
4.1.1 菜单插入
首先,将光标定位在函数内部,然后依次点击菜单栏的 Code、Insert Roxygen Skeleton,就插入了注释框架。
4.1.2 快捷键插入
首先,将光标定位在函数内部,然后使用快捷键 Ctrl+Alt+Shift+R 即可插入。
4.2 注释撰写
普通的注释以 井号# 开头,而函数注释以 井号和单引号 #’ 开头,并且后接1个空格。每一个区域的指定,都是以 @ 开头。
4.2.1 标题
第1行如果不指定,默认是标题 title,也可以自己使用 @title 指定。
书写标题时,需要在**@title** 后空1格,标题要能准确反映出函数的功能,要注意首字母大写。
4.2.2 描述
函数的描述部分并不是必须的,所以默认是不会插入这部分的,如果缺少了描述部分,R会自动用标题来代替。
使用 @description 来指定描述区域。描述部分必须是一整个段落,这意味着必须以句号也就是点来结尾。如果内容多,可以换行,每行最好不要超过80个字符,并且换行后要以4个空格开头。
如果 description 部分写得不够爽,还可以在 @details 部分进一步详细书写。
4.2.3 参数
使用 @param 来指定参数部分,@param 后空1格,写参数的名称,再空1格,写参数的解释,参数的解释不能为空。
4.2.4 链接到其它函数
有时候,或许我们并不需要把某一个参数的注释写的过于详细,因为其它地方有非常完备的说明,那么我们就可以使用 \code{\link[pkg]{rdname}} 这种形式来进行引用(如果是base环境下的函数,直接把包名写成base就可以啦!)。
4.2.5 返回
使用 @return 来说明函数的返回内容。
4.2.6 导出函数
如果函数是要分享出来和别人一起使用的,那么就需要将函数从包内导出,在注释部分添加 @export 即可,后面不需要写任何内容。
如果函数仅在包内使用,那么就不需要添加 @export,删除即可。
4.2.7 引用函数
如果想引用其它包中函数,那么需要使用 @importFrom,写法是 @importFrom+包名+函数名(一个或多个),如要引用 base 包中的 sum 函数,那么就可以这样写 —— @importFrom base sum。
如果我们还想引用 base 包中的其他函数,那么可以分开写两个 @importFrom,也可以写成一行。
4.2.8 示例
每个函数都应该有1个示例,这样更加方便用户来理解它(众所周知,说明文档垃圾还不如不写!)。
使用 @examples 来指定示例部分,如加入示例 sum2(1, 2),那么就可以在 @examples 后面写上。
如果示例不能够被运行,或者运行时间过长,在CRAN检测时不能被通过,可以使用 *donttest{}* 来使得示例在检测时自动被忽略。
4.3 转义注释
函数的注释写完了之后,它并不能被R自动识别,需要将其转义才可以。转义的方法我们在前面 封装包 中已经讲解,可以使用快捷键 Ctrl/Command+Shift+D,也可以使用命令 devtools::document()
,还可以使用菜单 Build、Document,这里我推荐使用 devtools::document()
。
devtools::document()
i Updating xmypkg documentation
i Loading xmypkg
Writing NAMESPACE
Writing NAMESPACE
Writing add.Rd
我们可以看到,写入了一个 Rd 文件,也就 R document 文件,文件名是 add.Rd。
点击 man 文件夹下的 add.Rd文件,可以看到略微复杂的内容,这就是最开始写 R 包时最痛苦的地方。
转义完之后,再次封装包即可(使用devtools::build()
)。
至此,创建包、写函数、写注释、转义注释、封装包,bingo!
5 引用 R 包函数
不同函数可以进行复杂的合作,并不是所有函数都需要我们从头写起,借用他人的函数,可以使我们的工作变得更加简单。
5.1 引用 CRAN 包
我们使用 usethis 包中的use_package()
函数来指定引用包,use_package()
函数中总共有3个参数package、type 和 min_version,package 表示我们要引用包的名称,type 表示引用的类型,常用的引用类型有 Imports、Depends 和 Suggests,min_version 表示包的最小版本号。
例如,在 xmypkg 包引用 stats 包,那么 package 就等于"stats"。
如果我们只需要使用 stats 包中的某个函数,而不是整个 stats 包,那么引用类型就是 Imports,命令如下:
usethis::use_package(package = "stats", type = "Imports")
√ Adding 'stats' to Imports field in DESCRIPTION
* Refer to functions with `stats::fun()`
我们看到 Adding “stats” to Imports field in DESCRIPTION,意思是将 stats 包添加在 DESCRIPTION 文件中的 Imports 部分,打开 DESCRIPTION 文件,可以看到多了 Imports 部分,而且下面有 stats。
如果我们需要使用整个 stats 包,也就是 xmypkg 包功能的实现完全依赖于 stats 包,而不是仅仅使用某个函数,type 等于“Depends”,命令如下:
usethis::use_package(package = "stats", type = "Depends")
√ Moving 'stats' from Imports to Depends field in DESCRIPTION
* Are you sure you want Depends? Imports is almost always the better choice.
stats 被从 Imports 转移到了 Depends 部分,并且告诉我们尽量不用使用 Depends,Imports 是最多且更好的选择。之所以有这样的建议,那是因为当 xmypkg 包对 stats 的关系是 Depends 时,library(xmypkg)
时,会同时library(stats)
,这样就增加了函数名称冲突的风险,而当 xmypkg 包对 stats 的关系是 Imports,library(xmypkg)
包的时候,不会运行library(stats)
,也就不会载入 stats 包,从而避免了不必要的函数名冲突,仅引用我们想引用的函数。
可以看到,在 DESCRIPTION 文件中,出现了 Depends 部分,并且下面有了 stats。
如果 xmypkg 包对 stats 包没有引用和依赖关系,仅仅在例子中使用了该包,那么我们会建议安装这个包,来实现我们的例子,这个时候的关系是“建议”,type 等于“Suggests”。
所以,DESCRIPTION文件中的 Imports、Depends 和 Suggests 分别表示:引用、依赖和建议。
5.2 引用 Bioconductor 包
单独使用 Imports、Depends 和 Suggests 引用的都是 CRAN 上的包,如果想引用 Bioconductor 上的包,需要在前面加上 biocViews: ,例如,我们想在 xmypkg 包中引用 limma 包,我们需要将 limma 写在 Imports 下面,并在 Imports 前加 biocViews: 。
5.3 引用函数
引用包是引用函数的前提,如果想引用某个函数,必须先引用该函数所属的R包。引用函数有2种形式:通过 双冒号:: 直接引用;通过 roxygen2 注释引用。
例如,我们要引用do包中的join_inner函数,通过双冒号来引用的方式为do::join_inner()
;通过注释来引用的方式为#' @importFrom do join_inner
。
引用函数的方式比较简单,但是有一点需要注意:只能引用R包导出的函数,也就是只能引用双冒号能够访问的函数,如果不能就要用三冒号啦!
6 DESCRIPTION 文件撰写
DESCRIPTION 文件是 R 包的说明文件,使用者通过阅读该文件,可以快速了解你的 R 包,DESCRIPTION 主要包含了标题、说明、作者、通讯方式、版本号等几个部分,现在我们来介绍一下如何撰写 DESCRIPTION 文件。
6.1 Title
标题一般有字数、内容和大小写的要求
- 字数不宜过长,一般不要超过20个词,过长的标题不宜阅读
- 标题要能够体现包的功能
- 标题的首字母需要大写,注意冠词、连词、介词的首字母需要小写
6.2 Description
描述部分是一段文字,要以句号结束。描述部分要求详细详细再详细!描述部分一定要详尽描述包的功能。这部分可以分多个段落来写,另起一段的时候,要以4个空格起写。注意不能以 This package 或者 This function 开头,切记!
6.3 Authors
需要使用person()
函数来创建。在person()
函数中,主要有几项是需要写的。
given:名
family:姓
middle:中间的名字
email:邮件,并不需要每个人的emial,仅给出包的拥有者即可。
role:角色
注意!每个包可以有多个作者,但是拥有者只能有1个。
-role 的取值如下:
aut:作者author
com:编译者compiler
cph:版权拥有者copyright holder
cre:包拥有者creator或者maintainer
ctb:贡献者contributor
ctr:承包者/公司contractor
dtc:贡献数据这data contrbutor
fnd:资助人/组织funder
rev:评论者reviewer
ths:指导者thesis advisor
trl:翻译者translator
6.4 Version
R 包必须有版本号,每次更新 R 包必须有不同的版本号,非正式发布的 R 包,版本号可以是零点几的版本,例如 0.9,正式的 R 包建议使用一点几以上的版本,R 包的版本可以是 1.0, 1.01,1.0.0.1。