R Packages 泛读笔记
分享一下本人阅读R Packages这本书所做的一点简单的笔记,说不定能帮到谁嘞。
原书籍在线阅读网站:https://r-pkgs.org/
基础流程
R包构建最基础流程:
- 编辑 R/ 文件
document() 更新文档
load_all() 加载更改
- 交互测试
test() 运行测试
check() 全面检查
存放数据
不同数据有不同存放方法。
| 数据类型 |
存放位置 |
适用场景 |
创建方法 |
特点 |
| 示例数据 |
data/ |
给用户使用的数据 |
usethis::use_data() |
用户可直接调用,需文档说明 |
| 内部数据 |
R/sysdata.rda |
仅包内部使用的数据 |
usethis::use_data(internal=TRUE) |
用户看不到,无需文档 |
| 原始文件 |
inst/extdata/ |
需要保持原始格式的文件 |
手动复制文件 |
如图片、Excel等非R格式文件 |
| 临时数据 |
环境变量 |
运行时需要记录的状态 |
new.env(parent=emptyenv()) |
只在当前R会话有效 |
R包重要目录如下。
| 目录 |
存放文件的类型 |
备注 |
src/ |
C/C++源代码 |
用于性能优化,需配合Rcpp或cpp11使用 |
inst/ |
安装时要包含的额外文件 |
内容会被复制到安装包的根目录 |
tools/ |
配置脚本和辅助工具 |
常用于维护脚本,可加入.Rbuildignore |
demo/ |
演示代码 |
已过时,如今须改用vignettes/ |
exec/ |
可执行脚本 |
文件自动标记为可执行 |
po/ |
国际化翻译文件 |
用于多语言支持 |
DESCRIPTION
DESCRIPTION 主要内容如下。
| 字段 |
作用 |
示例 |
| Package |
包名称(必填) |
Package: mypackage |
| Title |
单行简短描述(首字母大写,无句号) |
Title: Data Analysis Tools for R |
| Description |
详细描述(多行缩进,80字符/行) |
Description: Provides functions for cleaning and visualizing data. |
| Version |
版本号(语义化版本,如 1.0.0) |
Version: 0.1.0 |
| Authors@R |
作者和维护者(推荐用 person() 函数) |
Authors@R: person("Jane", "Doe", email="jane@example.com", role=c("aut", "cre")) |
| License |
许可证(如 MIT, GPL-3) |
License: MIT |
| Imports |
必需依赖(安装时自动安装) |
Imports: dplyr (>= 1.0.0), tidyr |
| Suggests |
可选依赖(测试/文档/扩展功能用) |
Suggests: testthat, ggplot2 |
| Depends |
仅用于声明R版本依赖(如 R (>= 4.0.0))或遗留包 |
Depends: R (>= 3.5.0) |
| URL |
包官网/代码仓库链接(逗号分隔) |
URL: https://github.com/user/mypackage |
| BugReports |
问题反馈链接(如GitHub Issues) |
BugReports: https://github.com/user/mypackage/issues |
| LazyData |
延迟加载数据(设为 true 加速数据访问) |
LazyData: true |
| SystemRequirements |
外部依赖(如C++库) |
SystemRequirements: C++11 |
依赖
若开发的R包必须和另一个包一起用,则要添加依赖。
Imports:核心功能必需的依赖
Suggests:可选功能/测试/文档的依赖
Depends:仅用于元包或强依赖场景
如下代码添加依赖:
# 核心依赖
usethis::use_package("dplyr", "Imports")
# 可选依赖
usethis::use_package("ggplot2", "Suggests")
执行后DESCRIPTION文件会自动生成:
Imports:
dplyr
Suggests:
ggplot2
另外在代码中还需显式声明使用了依赖函数,比如以dplyr::filter()举例如下:
clean_data <- function(data) {
dplyr::filter(data, condition) # 这里使用dplyr的filter
}
NAMESPACE
要更新NAMESPACE,运行devtools::document()。NAMESPACE文件相关操作:
| 操作 |
方案 |
生成NAMESPACE内容 |
| 声明用户可用的函数 |
#' @export |
export(function_name) |
| 使用其他包的单个函数 |
#' @importFrom pkg function |
importFrom(pkg,function) |
| 使用整个包 |
#' @import pkg (慎用) |
import(pkg) |
| S3方法 |
#' @exportS3Method |
S3method(generic,class) |
许可证
许可证分为两种。
| 类型 |
特点 |
常见许可证 |
适用情况 |
| Permissive |
允许自由使用修改,只需保留原许可 |
MIT, Apache, BSD |
希望代码被广泛使用 |
| Copyleft |
衍生作品必须使用相同许可 |
GPL, AGPL |
希望保持代码开源 |
许可证相关核心文件有:
DESCRIPTION中的License字段
LICENSE文件(包含具体条款)
LICENSE.md(完整许可证副本,CRAN不上传)
常用以下代码生成对应许可证。
# 代码许可证
usethis::use_mit_license() # 最宽松的MIT
usethis::use_gpl_license() # 要求衍生作品开源
# 数据许可证
usethis::use_cc0_license() # 数据完全开放
usethis::use_ccby_license() # 要求署名
测试
test相关设置
# 首次设置测试环境
usethis::use_testthat(3) # 使用testthat第3版
会创建:
tests/testthat/目录
DESCRIPTION中添加testthat依赖
tests/testthat.R入口文件
要创建对应脚本的测试文件,可用如下代码。
# 创建与R/foo.R对应的测试文件
usethis::use_test("foo") # 生成tests/testthat/test-foo.R
测试用例基本结构:
test_that("描述测试内容", {
# 准备测试数据
test_data <- ...
# 调用被测函数
result <- your_function(test_data)
# 验证结果
expect_equal(result, expected_value)
expect_true(is.numeric(result))
})
常用期望函数如下。
| 函数 |
用途 |
示例 |
expect_equal() |
宽松相等性检查 |
expect_equal(10, 10 + 1e-7) |
expect_identical() |
严格相等性检查 |
expect_identical(10, 10L) |
expect_error() |
验证错误 |
expect_error(1/"a") |
expect_warning() |
验证警告 |
expect_warning(log(-1)) |
expect_snapshot() |
快照测试 |
expect_snapshot(print(obj)) |
禁止在测试文件中显式调用 library(testthat),因为 testthat 的依赖版本应通过 DESCRIPTION 文件声明(如 Suggests: testthat (>= 3.0.0)),而非在测试代码中硬编码,确保所有测试均使用同一版本。
roxygen
roxygen2 是 R 语言中用于自动化生成函数文档的工具。开发者直接在函数代码上方用特殊格式的注释(以 #' 开头)编写文档,然后通过 devtools::document() 自动生成 .Rd 文件(R 的官方文档格式)。支其编写支持 Markdown语法。
roxygen2 注释块格式:
#' 函数的标题(首句,简短描述)
#'
#' 函数的详细描述(可多段)。
#' 使用Markdown语法(如 `code`、*强调*、[链接]())。
#'
#' @param 参数名 参数说明(类型、用途、默认值等)。
#' @returns 返回值说明(类型、结构)。
#' @examples
#' 可执行的R代码示例(需自包含、无副作用)。
#' @export # 标记为导出函数(公开给用户)
my_function <- function(x, y) {
函数体
}
示例:
#' Add together two numbers
#'
#' @param x A number.
#' @param y A number.
#' @returns A numeric vector.
#' @examples
#' add(1, 1)
#' add(10, 1)
add <- function(x, y) {
x + y
}
关键标签如下:
| 标签 |
用途 |
注意事项 |
@param |
描述函数参数。如 @param x A numeric vector. |
同类参数可合并:@param x,y Numeric vectors. |
@returns |
说明返回值。如 @returns A logical vector of same length as input. |
CRAN要求所有导出函数必须明确返回值。 |
@examples |
提供可运行的示例代码。 |
必须无错误、快速(<10秒)、无副作用(比如不修改全局选项)。 |
@export |
将函数导出到NAMESPACE,允许用户调用。 |
未导出的函数用 @noRd 标记。 |
@inheritParams |
复用其他函数的参数文档。如 @inheritParams other_function |
避免重复描述相同参数。 |
@section |
添加带标题的详细说明块。如 @section Warning: Do not input NULL. |
适用于复杂函数的额外说明。 |
Vignettes
Vignettes是R包的长篇教程,用于展示核心功能。可通过browseVignettes("包名")或vignette("名称", package="包名")查看。
初始化Vignette:
usethis::use_vignette("my-vignette") # 创建模板文件`vignettes/my-vignette.Rmd`
这样就能:
- 自动生成
vignettes/目录。
- 在
DESCRIPTION中添加依赖(如knitr和rmarkdown)。
Vignettes默认开头如下,采取YAML格式,其中>表示下方均为文本。
---
title: "Vignette Title"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Vignette Title}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
README
README文件是用户接触包的第一站,需要有三个核心要素:
- 为什么使用这个包(介绍)?
- 如何快速上手(教程)?
- 如何安装(CRAN/GitHub)?:
使用README.Rmd生成README.md
usethis::use_readme_rmd() # 创建模板
devtools::build_readme() # 渲染更新
NEWS
NEWS文件记录版本变更。结构如下:
# foofy (development version)
* Better error message when grooving an invalid grobble (#206).
# foofy 1.0.0
## Major changes
* Can now work with all grooveable grobbles!
## Minor improvements and bug fixes
* Printing scrobbles no longer errors (@githubusername, #100).
* Wibbles are now 55% less jibbly (#200).
建设R包网站
初始化配置:
usethis::use_pkgdown() # 创建配置文件_pkgdown.yml
pkgdown::build_site() # 首次构建网站
usethis::use_pkgdown_github_pages() #GitHub用户一键配置
pkgdown会自动整合以下内容生成网站:
| 文档类型 |
网站位置 |
生成源 |
| 函数文档 |
/reference/ |
man/*.Rd文件 |
| 数据集文档 |
/reference/ |
R/data.R中的文档 |
| Vignettes |
/articles/下拉菜单 |
vignettes/*.Rmd |
| README |
首页 |
README.Rmd |
| NEWS |
"News"导航栏 |
NEWS.md |
添加logo步骤如下:
- 将logo图片保存为
man/figures/logo.png
-
使用命令
usethis::use_logo("path/to/your_logo.png")
这样一来,logo图片会自动调整尺寸并更新README显示,且网站导航栏会自动显示logo。
只要.github/workflows/pkgdown.yaml包含下列代码,每次git push后便会自动重建网站。
on:
push:
branches: [main]