十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

R 包开发实战:从零构建、测试到发布

R 包开发实战:从零构建、测试到发布 1. 引言R 包是 R 语言生态中组织、复用和分发代码的标准方式。无论是个人项目中的工具函数还是面向社区发布的开源库将代码封装为 R 包都能显著提升可维护性和可分享性。本文将从零开始带你完整走一遍 R 包的创建、编写、测试、文档化和发布流程并给出大量可直接运行的代码示例。2. 准备工作安装必要工具在开始之前需要确保 R 环境中安装了以下关键包。它们分别负责构建、测试和文档生成。# 安装核心工具链 install.packages(c(devtools, roxygen2, testthat, usethis)) 验证安装 library(devtools) library(roxygen2) library(testthat) library(usethis) 查看 devtools 版本 packageVersion(devtools)其中devtools是开发流程的总入口roxygen2用于从注释生成文档testthat提供单元测试框架usethis则能自动化创建包的标准目录结构。3. 创建包的基本结构使用usethis::create_package()可以一键生成标准目录结构。下面以创建一个名为mytools的包为例。# 创建包目录请替换为你的实际路径 usethis::create_package(~/R/mytools)创建完成后包目录下会生成以下关键文件DESCRIPTION包的元数据文件包含包名、版本、作者、依赖等信息。NAMESPACE声明包的导入和导出规则。R/存放 R 源代码文件的目录。man/存放生成的帮助文档通常由 roxygen2 自动生成。tests/存放单元测试代码。4. 编写第一个 R 函数在R/目录下新建一个源文件例如R/hello.R写入以下内容。这里我们定义一个简单的问候函数和一个计算均值的函数。# R/hello.R # 向指定对象打招呼 # # param name 字符串被问候者的名字 # return 返回一个问候语字符串 # export # # examples # hello(World) hello - function(name World) { paste0(Hello, , name, !) } # 计算数值向量的均值忽略缺失值 # # param x 数值向量 # return 返回均值 # export # # examples # my_mean(c(1, 2, 3, NA)) my_mean - function(x) { mean(x, na.rm TRUE) }注意函数上方的注释使用了 roxygen2 的语法param描述参数return描述返回值export表示该函数需要被导出到 NAMESPACE供用户直接调用。5. 使用 roxygen2 生成文档写好源码后运行以下命令自动生成man/目录下的帮助文档并更新NAMESPACE文件。# 在包根目录下执行 devtools::document()执行后man/hello.Rd和man/my_mean.Rd会被自动创建。此时可以通过?hello查看生成的帮助文档。6. 编写单元测试使用usethis::use_testthat()初始化测试框架然后为每个函数编写测试用例。# 初始化 testthat 框架 usethis::use_testthat() 为 hello 函数生成测试文件 usethis::use_test(hello)生成的测试文件位于tests/testthat/test-hello.R编辑内容如下# tests/testthat/test-hello.R test_that(hello 函数正常工作, { expect_equal(hello(R), Hello, R!) expect_equal(hello(), Hello, World!) expect_type(hello(Alice), character) }) test_that(my_mean 函数忽略缺失值, { expect_equal(my_mean(c(1, 2, 3, NA)), 2) expect_equal(my_mean(c(10, 20)), 15) expect_true(is.na(my_mean(c(NA, NA)))) })运行全部测试devtools::test()如果所有测试通过控制台会输出绿色的通过信息若有失败会明确指出失败的断言和所在行号。7. 添加数据与内部函数包内可以附带示例数据集也可以定义仅供内部使用的函数。下面演示如何添加一个内置数据集。# 创建数据目录并写入示例数据 usethis::use_data_raw() 在># R/utils.R内部函数不导出 标准化向量内部使用 z_score - function(x) { (x - mean(x, na.rm TRUE)) / sd(x, na.rm TRUE) } 在导出的函数中调用内部函数 # 返回标准化后的分数 # # param x 数值向量 # return 标准化后的向量 # export standardize - function(x) { z_score(x) }8. 检查包的完整性在发布前务必运行devtools::check()对包进行全面检查包括代码规范、文档完整性、测试通过情况等。# 全面检查包 devtools::check()检查结果会分为 ERROR、WARNING 和 NOTE 三个等级。理想情况下应做到 0 ERROR、0 WARNINGNOTE 越少越好。常见的 NOTE 包括未声明全局变量、文档示例运行时间过长等。9. 安装与使用本地包开发过程中可以随时将包安装到本地 R 库中方便在其它项目中调用。# 安装到本地库 devtools::install() 加载并使用 library(mytools) hello(R 社区) [1] Hello, R 社区! my_mean(c(5, 10, 15, NA)) [1] 1010. 发布到 CRAN 或 GitHub如果希望将包分享给更多人可以选择发布到 CRAN 或 GitHub。发布到 CRAN 需要满足更严格的规范而 GitHub 则更加灵活。# 发布到 GitHub 前先初始化 Git 仓库并提交 usethis::use_git() 创建 GitHub 远程仓库需要提前配置 GitHub 令牌 usethis::use_github() 提交并推送代码 之后在 GitHub 仓库页面创建 Release 即可 若准备提交 CRAN先运行最终检查 devtools::check() 然后提交 devtools::release()提交 CRAN 前建议额外检查以下几点DESCRIPTION 中的作者信息和许可证是否完整。所有文档示例是否能在 5 秒内运行完毕。代码中不包含绝对路径或网络下载操作。11. 完整示例一个实用的字符串工具包下面整合以上知识点构建一个完整的小型字符串处理包包含多个函数、测试和文档。# R/string_tools.R # 反转字符串 # # param s 字符串 # return 反转后的字符串 # export str_reverse - function(s) { chars - strsplit(s, )[[1]] paste(rev(chars), collapse ) } # 统计字符串中某个字符的出现次数 # # param s 字符串 # param char 要统计的字符 # return 出现次数 # export str_count_char - function(s, char) { nchar(gsub(paste0([^, char, ]), , s)) } # 将字符串转换为驼峰命名 # # param s 字符串单词间用空格或下划线分隔 # return 驼峰命名字符串 # export str_to_camel - function(s) { words - strsplit(s, [ _])[[1]] paste0(words[1], paste0(toupper(substring(words[-1], 1, 1)), substring(words[-1], 2), collapse )) }对应的测试文件tests/testthat/test-string_tools.Rtest_that(str_reverse 正确反转, { expect_equal(str_reverse(abc), cba) expect_equal(str_reverse(R 语言), 言语 R) }) test_that(str_count_char 正确计数, { expect_equal(str_count_char(hello, l), 2) expect_equal(str_count_char(banana, a), 3) }) test_that(str_to_camel 正确转换, { expect_equal(str_to_camel(hello world), helloWorld) expect_equal(str_to_camel(foo_bar_baz), fooBarBaz) })运行测试并安装devtools::test() devtools::install() 使用示例 library(stringtools) str_reverse(hello) # olleh str_count_char(banana, a) # 3 str_to_camel(hello world) # helloWorld12. 总结本文从环境准备、目录创建、函数编写、文档生成、单元测试到发布流程完整演示了 R 包的开发全流程。核心要点可以归纳为使用usethis快速搭建标准目录结构。用roxygen2注释驱动文档和 NAMESPACE 的自动生成。用testthat为每个导出函数编写测试保证代码质量。发布前务必运行devtools::check()消除错误和警告。掌握这些技能后你就可以将自己的 R 代码封装成规范、可复用的包无论是个人使用还是开源分享都会更加高效。
返回列表