写一个简单的 R 包:DTII v0.1.0 的开发过程

写一个简单的 R 包:DTII v0.1.0 的开发过程 前段时间参加了字节和 Intel 办的 Bio OS 开源开放大赛(任务挑战赛),初赛后写了一个小 R 包 DTII https://github.com/WhyLIM/DTII ,用于从 Open Targets Platform GraphQL API 查询药物 靶标 适应症相互作用。以此为例介绍一下 R 包的开发流程。 准备环境 R ...

写一个简单的 R 包:DTII v0.1.0 的开发过程

前段时间参加了字节和 Intel 办的 Bio-OS 开源开放大赛(任务挑战赛),初赛后写了一个小 R 包 [DTII](https://github.com/WhyLIM/DTII),用于从 Open Targets Platform GraphQL API 查询药物-靶标-适应症相互作用。以此为例介绍一下 R 包的开发流程。

准备环境

  • **R 4.4.0**
  • **Rstudio**
  • **devtools**: 用于简化包的开发工作流。
  • **roxygen2**: 用于生成文档。
安装完成后,使用命令 `devtools::has_devel()` 来进行检查
理论上会输出 `“Your system is ready to build packages! ”`

起一个名字

在命名 R 包时,CRAN 和 R 社区通常建议遵循一些基本的命名规则:

字符限制

  • **名称长度适中**:一般包的名称不宜过长,通常在 **2-20 个字符**之间。
  • **只能使用字母和数字**:包名称应由 **字母**(A-Z,a-z)和 **数字**(0-9)组成。
  • **避免使用特殊字符**:包名称不能包含下划线 (`_`)、连字符 (`-`)或其他特殊符号。
  • **不区分大小写**:R 包的名称在 CRAN 中不区分大小写。也就是说,`mypackage` 和 `MyPackage` 被认为是相同的名称。
  • **推荐小写**:虽然不强制,但建议使用 **全小写字母**,便于记忆和输入。例如,`dplyr`、`ggplot2` 等。

避免保留字和常用函数名称

  • **避免使用 R 的保留字**:如 `if`、`else`、`function` 等,以防冲突。
  • **避免与常用包的名称冲突**:如 `stats`、`data` 等,容易引起混淆。

有意义和表达性

  • **描述包的功能或用途**:名称应尽量传达包的核心功能或主题。比如 `stringr` 表示字符串处理、`forecast` 表示时间序列预测等。
  • **不要过度通用**:避免使用过于笼统的词汇,如 `data`、`tools` 等,尽量有具体意义。

避免商标和品牌名

  • **避免使用商标、品牌名称或受保护的词语**,确保包名不会侵犯任何版权或商标权。

如果需要多个单词,考虑拼接或数字结尾

  • **多词拼接**:可以将多个单词直接拼接,如 `data.table`。
  • **使用数字后缀**:如果包有更新版本或表示一个概念的改进版,可以在包名后使用数字,如 `ggplot2`。

遵循 CRAN 提交要求

CRAN 对包名有一些技术性要求,确保包名称在提交时满足这些规范,并且包名要唯一(不能与现有包重名)。

初始化

设置目录,并进行 R 包的初始化
执行完以上代码,Rstudio 会自动打开一个 R Project

编写函数

使用 `use_r()` 函数来创建一个新的函数,例如我们来创建一个 `search()` 函数
此函数用于根据提供的关键字使用 Open Targets GraphQL API 来搜索实体
由于 API 的限制,我们最多只能获取前 10,000 个结果
函数中的注释原本使用的是中文,但我在写这篇教程的时候发现下一步的 `load_all()` 在中文注释状态下竟然会报错(这个现象在开发时并未出现)

函数测试

编写完 `search()` 函数后,我们使用 `load_all()` 使其可以用于测试
`load_all()` 会使用默认参数运行一次函数,因此对于 `search()` 函数,即会运行 `search(keywords = NULL, size = 10000)`,但是由于我的编写逻辑为检测到空关键词就终止并提示用户输入,因此 `load_all()` 的结果如下:
这个错误其实~~是一个正确的错误~~并不是真正的错误,我们在测试时可以去掉这部分的逻辑并给一个正常的 `keywords` 变量
`load_all()` 完成后,即可自定义变量进行测试
正常情况下,`result` 是一个列表,存储了 4 个 data.frame:
  • target:lung cancer 相关靶标的分类与数量
  • disease:lung cancer 相关疾病的分类与数量
  • drug:lung cancer 相关药物的分类与数量
  • hits:lung cancer 在数据库中的所有相关实体的 ID、类型以及名称
如果运行结果没有问题,那么这个函数基本上是成功的

函数注释

将光标定位到函数内部,在 Rstudio 的顶栏 Code -> Insert Roxygen Skeleton 可以插入注释模板
默认的模板如下
以上的函数注释遵循 Roxygen2 的语法规范。Roxygen2 是一种方便的工具,可以将注释自动生成 `.Rd` 文档文件,这些文件将最终被包含在 R 包中,并在帮助系统中显示。
以下是 R 包函数注释的基本规则和关键部分:

Roxygen2 注释格式

  • 使用 `#'` 开头的注释行。
  • 注释内容应放在每个函数的前面。
  • 每一行注释都要以 `#'` 开始,否则不会被识别为 Roxygen2 格式。

注释的关键部分

Title - 标题

  • 使用 `@title` 标签为函数提供一个简明的标题。
  • 应尽量简短而清晰地描述函数的主要作用。

Description - 描述

  • 使用 `@description` 标签提供函数的详细描述。
  • 可以多行书写,尽量准确说明函数的作用和返回内容。
PS:其实不使用 `@title` 和 `description`,直接写标题和描述也可以

Parameters - 参数

  • 每个参数用 `@param` 标签描述。
  • 说明每个参数的名称、类型以及用法,通常为单行描述。

Return - 返回值

  • 使用 `@return` 标签描述函数的返回值。
  • 简明描述返回内容的类型及其结构。

Examples - 示例

  • 使用 `@examples` 标签提供代码示例。
  • 例子应该能够直接运行,并展示函数的典型用法。
但对于一些可能不适合直接运行的示例代码,我们也可以使用 `\\dontrun{}` 标签来标记,例如

Other Common Tags

  • `@export`:标记函数为导出函数,使其对用户可见。
  • `@seealso`:添加链接到其他相关函数。
有时候我们并不需要把某一个参数的注释写的过于详细,因为其它地方有非常完备的说明,那么我们就可以直接进行引用,例如,以下示例引用了 base 包的 `mean()` 函数
  • `@import` 和 `@importFrom`:说明依赖的其他包或函数。
  • `@details`:提供额外的详细说明,通常是在 `@description` 中没有说明的内容。

示例

以下是一个完整的函数注释示例:

生成文档

在所有函数前添加注释后,使用以下命令生成帮助文档:
这将自动创建或更新 `man/` 文件夹中的 `.Rd` 文件,使函数文档在 R 包中生效。

添加许可证

有多种常见的许可证可以使用,我们可以借助 `usethis` 包提供的函数来自动生成许可证文件。

常用的许可证生成函数(`usethis` 包)

  1. **GNU 通用公共许可证 v2.0 或 v3.0**
  • `use_gpl3_license()`:生成 GNU 通用公共许可证第三版(GPL-3)的文件。
  • `use_gpl2_license()`:生成 GNU 通用公共许可证第二版(GPL-2)的文件。
  1. **Apache 许可证**
  • `use_apache_license()`:生成 Apache License 2.0 的许可证文件。
  1. **MIT 许可证**
  • `use_mit_license()`:生成 MIT 许可证文件,这是最常用的宽松开源许可证之一。
  1. **艺术家公共许可**
  • `use_artistic_license_2()`:生成 Artistic License 2.0 文件。
  1. **CC BY 许可证**
  • `use_ccby_license()`:生成知识共享署名(Creative Commons Attribution, CC BY)许可证文件。

示例

使用 MIT 许可证,并将许可证信息写入 `DESCRIPTION` 文件:

注意

许可证的选择对代码的使用和传播有重要影响。一般建议:
  • 如果希望代码自由使用、修改并再次发布,选择 **MIT** 或 **Apache**。
  • 如果希望代码开源且传播时保持同样的许可证要求,选择 **GPL-3**。

DESCRIPTION 文件

`DESCRIPTION` 文件是 R 包的元数据文件,包含关于包的信息,如包名、版本、作者、依赖项等。这个文件对于 CRAN 审核以及用户理解包的基本信息非常重要。
它的基本格式是 `Field: Value`,每一行定义一个字段。以下是撰写 `DESCRIPTION` 文件的关键字段及其内容介绍。

常见字段

`Package`

  • **包名**,必须是唯一的、易于记忆的标识符。
  • 应符合 CRAN 的命名规范(仅允许字母、数字和句点,不允许空格)。

`Title`

  • **简短标题**,描述包的功能或用途,通常不超过 65 个字符。
  • 必须以大写字母开头,结尾不要加句号。

`Version`

  • **版本号**,用于标识包的不同发布版本。
  • 通常采用三段式格式:`Major.Minor.Patch`(例如,`1.0.0`)。
  • 非正式发布的 R 包,版本号可以是零点几的版本,例如 0.1.0

`Authors@R`

  • **作者和维护者信息**。
  • `Authors@R` 使用 R 代码格式来定义多个作者及其角色,推荐使用这种格式。
  • **常见角色代码**:
  • `"aut"`:作者
  • `"cre"`:维护者(必须指定一个维护者)

`Description`

  • **详细描述**,介绍包的功能和作用。

`License`

  • **许可证**,声明包的使用和分发权限。
  • 在上一步中,如果使用了 MIT 许可证,那么该字段已经被自动填充:

`Depends`

  • **包依赖**,声明包运行所需的最低 R 版本及依赖的其他 R 包。
  • 通常用于指定 R 版本,其他包依赖一般放在 `Imports` 字段中。

`Imports`

  • **导入依赖**,列出包运行时所需的其他包。
  • `Imports` 中的包在加载时不会自动附加到用户的命名空间,需要使用 `::` 调用(如 `dplyr::filter`)。

`Suggests`

  • **建议依赖**,列出包的可选依赖项。
  • 这些包在运行某些特定功能或示例代码时才需要,例如用于测试和文档生成的工具。

`LazyData`

  • **延迟加载数据**,一般设为 `true`,表示在使用包自带的数据集时可以延迟加载。

完整示例

以下是本 R 包的 DESCRIPTION 文件示例:

封装 R 包

使用 `devtools::build()` 来封装 R 包

上传到 Github

我们可能希望自己的包被别人使用,或者是留个云存档。
但在 CRAN 上发布 R 包是一件非常麻烦的事情,因此可以发布到 Github。假设已经安装配置好了 git
  1. 在 GitHub 上创建一个新的代码仓库,例如我们取名叫 DTII
  1. 初始化 git 仓库,在 R 包的根目录执行
  1. 提交到本地 git 仓库
  1. 上传到 Github
在新建的 DTII 仓库中点击绿色 Code 按钮可以获得 SSH 链接
上一篇
差异基因富集分析与 GSEA
下一篇
使用 Vue 3 + Element Plus 从头开始写一个数据库网站-06-前端与后端的交互
Loading...