R · R 包开发 | 保姆级教程

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

标题一般有字数、内容和大小写的要求

  1. 字数不宜过长,一般不要超过20个词,过长的标题不宜阅读
  2. 标题要能够体现包的功能
  3. 标题的首字母需要大写注意冠词、连词、介词的首字母需要小写

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。

6.5 Example

参考资料

  1. https://www.jianshu.com/p/8e0db63fcbff
  2. https://www.bilibili.com/video/BV1rf4y157ue

猜你喜欢

转载自blog.csdn.net/weixin_43843918/article/details/129395318
R
R: