R包开发实例

准备

加载devtools包,它是一组支持包开发的各个方面的包

library(devtools)

仅出于表示的目的,我们使用fs(用于文件系统工作)和tidyverse(用于轻量级数据处理)。

library(tidyverse)
library(fs)

包中常见的功能

  • 满足特定需求的功能,如处理factors的功能。

  • 访问已建立的安装工作流、获取帮助和检查基本质量。

  • 版本控制和开放的开发过程。

    • 这在您的工作中是完全可选的,但推荐使用。您将看到Git和GitHub如何帮助我们公开包的所有中间阶段。

  • 通过roxygen2编写单个函数的文档。

  • 使用testthat进行单元测试。

  • 通过可执行的README.Rmd将包作为一个整体提供文档。

Demo

包称为foofactors,它将有两个用于处理因子的函数。首先在计算机的一个目录中初始化一个新包:

> create_package("/foofactors")  # 会弹出一个新的窗口
√ Creating '/foofactors/'
√ Setting active project to 'D:/foofactors'
√ Creating 'R/'
√ Writing 'DESCRIPTION'
Package: foofactors
Title: What the Package Does (One Line, Title Case)
Version: 0.0.0.9000
Authors@R (parsed):
    * First Last  [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
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.1.1
√ Writing 'NAMESPACE'
√ Writing 'foofactors.Rproj'
√ Adding '^foofactors\\.Rproj$' to '.Rbuildignore'
√ Adding '.Rproj.user' to '.gitignore'
√ Adding '^\\.Rproj\\.user$' to '.Rbuildignore'
√ Opening 'D:/foofactors/' in new RStudio session
√ Setting active project to ''

新建的包中含有如下的文件

  • . Rbuildignore:列出了我们需要的文件,但在从源代码构建R包时不应该包括这些文件。
  • . rproj.user:如果有的话,是RStudio内部使用的目录。
  • . gitignore:预期Git的使用,并忽略一些由R和RStudio创建的标准后台文件。即使您不打算使用Git,这也是无害的。
  • DESCRIPTION:提供关于包的元数据。
  • NAMESPACE:命名空间声明包导出供外部使用的函数,以及包从其他包导入的外部函数。此时,它是空的,除了声明这是一个我们不会手工编辑的文件的注释。
  • R/目录是包的业务端。它很快就会包含带有函数定义的. r文件。
  • foofactors.Rproj是使该目录成为RStudio项目的文件。即使你不使用RStudio,这个文件也是无害的。或者你可以用create_package(…, rstudio = FALSE)。

RStudio可以在任何项目中初始化Git存储库,即使它不是一个R包,只要你已经设置了RStudio + Git集成。做工具>版本控制>项目设置。然后选择版本控制系统:Git,并为这个项目初始化一个新的Git存储库。

> use_git()  # 在原始界面输入,而不是包的界面输入
√ Setting active project to 'D:/foofactors'
√ Initialising Git repo
√ Adding '.Rhistory', '.Rdata', '.httr-oauth', '.DS_Store' to '.gitignore'
There are 5 uncommitted files:
* '.gitignore'
* '.Rbuildignore'
* 'DESCRIPTION'
* 'foofactors.Rproj'
* 'NAMESPACE'
Is it ok to commit them?

1: No
2: For sure
3: No way

Selection: 1

如果你正在使用RStudio,它可能会请求允许在这个项目中重新启动自己。通过双击foofactors.Rproj,你可以手动退出并重新启动。

然后可以在打开的窗口中编写R函数,保存在R/路径下面

fbind <- function(a,b){
  factor(c(as.character(a),as.character(b)))
}
> a <- factor(c('character', 'hits', 'your', 'eyeballs'))
> a
[1] character hits      your      eyeballs 
Levels: character eyeballs hits your
> b <- factor(c("but", "integer", "where it", "counts"))
> b
[1] but      integer  where it counts  
Levels: but counts integer where it
> c(a, b)
[1] 1 3 4 2 1 3 4 2
> factor(c(as.character(a), as.character(b)))
[1] character hits      your      eyeballs  but       integer   where it  counts   
Levels: but character counts eyeballs hits integer where it your
> fbind(a, b)
[1] character hits      your      eyeballs  but       integer   where it  counts   
Levels: but character counts eyeballs hits integer where it your

> use_r("fbind")  
* Modify 'R/fbind.R'
* Call `use_test()` to create a matching test file
# 在原窗口输入此命令,可以打开该文件
> load_all()  # 用于加载当前写的包,进而可以使用当前包内的函数
Loading foofactors

使用Git提交自己的包,并使用check()进行检查,出现的一个问题是没有许可规范,之后可以解决

> check()
-- R CMD check results ------------------------------------------------------------------------- foofactors 0.0.0.9000 ----
Duration: 11.1s

> checking DESCRIPTION meta-information ... WARNING
  Non-standard license specification:
    `use_mit_license()`, `use_gpl3_license()` or friends to pick a
    license
  Standardizable: FALSE

0 errors √ | 1 warning x | 0 notes √

接下来可以编辑描述DESCRIPTION,可以进行如下类似的描述:

Package: foofactors
Title: Make Factors Less Aggravating
Version: 0.0.0.9000
Authors@R:
    person("Jane", "Doe", email = "[email protected]", role = c("aut", "cre"))
Description: Factors have driven people to extreme measures, like ordering
    custom conference ribbons and laptop stickers to express how HELLNO we
    feel about stringsAsFactors. And yet, sometimes you need them. Can they
    be made less maddening? Let's find out.
License: What license it uses
Encoding: UTF-8
LazyData: true

如何获取许可证,使用MIT许可证

> use_mit_license('kathlian')
√ Setting License field in DESCRIPTION to 'MIT + file LICENSE'
√ Writing 'LICENSE'
√ Writing 'LICENSE.md'
√ Adding '^LICENSE\\.md$' to '.Rbuildignore'

对每个函数需要添加描述,将光标放在函数主体内的任意位置,然后点击code,选择Insert roxygen skeleton,可以将其修改成如下的模式:

#' Bind two factors
#'
#' Create a new factor from two existing factors, where the new factor's levels
#' are the union of the levels of the input factors.
#'
#' @param a factor
#' @param b factor
#'
#' @return factor
#' @export
#' @examples
#' fbind(iris$Species[c(1, 51, 101)], PlantGrowth$group[c(1, 11, 21)])

完成上述更改之后,还需要使用document()函数对注释信息进行保存。fbind查看此函数的帮助文档

> document()
Updating foofactors documentation
Loading foofactors
Writing NAMESPACE
Writing fbind.Rd

打开NAMESPACE文件出现如下,需要使用document()对文件内容进行更新:

# Generated by roxygen2: do not edit by hand

export(fbind)  # 此函数使得用户通过library(foofactors)可以使用fbind()函数

再次使用check(),则没有任何问题

> check()
#> ── R CMD check results ────────────────── foofactors 0.0.0.9000 ────
#> Duration: 11.2s
#> 
#> 0 errors ✔ | 0 warnings ✔ | 0 notes ✔

安装

以上就是一个小demo的完整流程,接下来我们可以使用install(),安装包,测试:

> install()
> library(foofactors)
> a <- factor(c("character", "hits", "your", "eyeballs"))
> b <- factor(c("but", "integer", "where it", "counts"))
> 
> fbind(a, b)
[1] character hits      your      eyeballs  but       integer   where it  counts   
Levels: but character counts eyeballs hits integer where it your

接下去,使用use_testthat()声明编写单元测试的意图,这将初始化包的单元测试机制。它添加suggests:testthat到DESCRIPTION中,创建目录tests/testthat/,并添加脚本tests/testthat. R。

> use_testthat()
√ Adding 'testthat' to Suggests field in DESCRIPTION
√ Setting Config/testthat/edition field in DESCRIPTION to '3'
√ Creating 'tests/testthat/'
√ Writing 'tests/testthat.R'
* Call `use_test()` to initialize a basic test file and open it for editing.

实际的测试还是需要我们自己编写,使用use_test()打开和/或创建一个测试文件。您可以提供文件的basename,如果您在RStudio中编辑相关的源文件,它将自动生成。由于本书是以非交互方式构建的,所以必须显式提供basename:

> use_test("fbind")
#> ✔ Writing 'tests/testthat/test-fbind.R'
#> ● Modify 'tests/testthat/test-fbind.R'

将以下内容放入 tests/testthat/test-fbind.R

test_that("fbind() binds factor (or character)", {
  x <- c("a", "b")
  x_fact <- factor(x)
  y <- c("c", "d")
  z <- factor(c("a", "b", "c", "d"))

  expect_identical(fbind(x, y), z)
  expect_identical(fbind(x_fact, y), z)
})

使用test:

> library(testthat)
> load_all()
Loading foofactors
> test()
Loading foofactors
Testing foofactors
√ |  OK F W S | Context
√ |   2       | fbind [0.3 s]                                       

== Results =========================================================
Duration: 0.3 s

[ FAIL 0 | WARN 0 | SKIP 0 | PASS 2 ]
> check()  # 当使用check,也会进行测试

导入其他包

我们如果需要使用其他包中的函数,需要使用use_package()来表示需要使用包中的某些函数:

> use_package("forcats")  # 这将会添加“Imports”部分进入DESCRIPTION
#> ✔ Adding 'forcats' to Imports field in DESCRIPTION
#> ● Refer to functions with `forcats::fun()`
> use_r("fcount")  # 添加第二个函数
#> ● Edit 'R/fcount.R'
#> ● Call `use_test()` to create a matching test file
# 将以下内容放入fcount.R文件中,就可以完成了import其他包中的函数
#' Make a sorted frequency table for a factor
#'
#' @param x factor
#'
#' @return A tibble
#' @export
#' @examples
#' fcount(iris$Species)
fcount <- function(x) {
  forcats::fct_count(x, sort = TRUE)
}
# 使用load_all()来重新加载包,并测试添加的新函数
load_all()
#> ℹ Loading foofactors
fcount(iris$Species)
#> # A tibble: 3 x 2
#>   f              n
#>         
#> 1 setosa        50
#> 2 versicolor    50
#> 3 virginica     50
# 生成相关的帮助文件,添加描述
document()
#> ℹ Updating foofactors documentation
#> ℹ Loading foofactors
#> Writing NAMESPACE
#> Writing NAMESPACE
#> Writing fcount.Rd

使用git

> use_github()

编辑README.md文件,包括算法的介绍和如何使用等内容:

> use_readme_rmd()
#> ✔ Writing 'README.Rmd'
#> ✔ Adding '^README\\.Rmd$' to '.Rbuildignore'
#> ✔ Writing '.git/hooks/pre-commit'

END

最后还需要检查确保包的正确,然后安装:

> check()
> install()

你可能感兴趣的:(r语言,开发语言)