前言
为什么要写包?不用多解释了:
- 载入并调用你编写的函数,而不是全放到环境里
- 方便管理
- 发布 CRAN/Bioconductor !
一年前写了一个超简单的教程:编写你自己的R包 - 简书 (jianshu.com),但仅介绍了如何把单个函数写进包里。先看下这个简单的教程会理解本文有很大帮助。
今天来个进阶版,把你function.R
里所有的函数都写进包里,甚至多个脚本里的函数也支持。
开始制作
建议在Rstudio里操作。
依赖的包
install.packages(c("devtools", "roxygen2", "testthat", "knitr"))
一些预设
rm(list = ls())
pkgName = "efficeintR"
version = "1.0.0"
author = "Jiahao Wang"
masterDir = "D:/03_Study/R_build"
funDir = "D:/02_Software/R-4.2.1/library/base/R/yyds"
- masterDir:主目录,在这下面去制作一些包
- funDir:函数目录,里面是一个或多个包含函数的脚本
起始R包
require("devtools")
dir.create(paste0(masterDir, "/", pkgName), recursive = TRUE)
create_package(paste0(masterDir, "/", pkgName, "/", pkgName))
运行后会单独打开一个Rstudio界面,自动进入R包目录。
![](https://img.haomeiwen.com/i5257017/25bfe0fd243a638e.png)
重新运行预设:
pkgName = "efficeintR"
version = "1.0.0"
author = "Jiahao Wang"
masterDir = "D:/03_Study/R_build"
funDir = "D:/02_Software/R-4.2.1/library/base/R/yyds"
首先,修改包的描述信息,打开右侧文件栏中的DESCRIPTION
,简单编辑一下版本、标题、作者、描述等:
![](https://img.haomeiwen.com/i5257017/9e65dd80507ae8c2.png)
一键导入函数
这里我写了一个函数可以一键将包含函数的若干R文件导入到包内:
buildFuns <- function(funFile, author){
funOut = paste0("R/", basename(funFile))
sink(funOut)
Lines = readLines(funFile)
for(i in 1:length(Lines)){
Line = Lines[i]
if(grepl("<- function", Line)){
if(! subString(Line, 1) %in% c("#", "\t", " ")){
funName = subString(Line, 1, " ")
cat("#' @title", funName, "\n")
cat("#' @author", author, "\n")
cat("#' @export\n")
}
}
cat(Line, "\n")
}
sink()
}
- 其实就是逐行写入包中,需要增加的就是函数头的一些内容。
- 注意,这里的写入有一定的规则,大家可能需要按自己的习惯去调整:
- 编写函数时使用
funName <- function(paras)
格式,这样就能被识别到该行是声明一个新函数 - 从而,在该行之前插入函数的头信息,这里仅包括:函数名、作者、导出该函数,详细的帮助文档也可自己手动加入,下文有示例
- 对于一些函数内函数和被注释掉的函数,不给予处理
一键导入函数:
funFiles = list.files("D:/02_Software/R-4.2.1/library/base/R/yyds", ".R$", recursive = TRUE, full.names = TRUE)
sapply(funFiles, buildFuns, author)
点开R文件夹,就会发现函数已经部署到这里了:
![](https://img.haomeiwen.com/i5257017/7bbe64d3e1af845a.png)
打开check.R康康:
![](https://img.haomeiwen.com/i5257017/3dddc24ad4c82ee3.png)
细化帮助文档
每个函数的帮助文档各不相同,只能单个去编辑了,这个是最费时间精力的了
如果暂时只是自己使用,可以这一步略过
但为了教学,那就演示一下函数帮助文档的编写吧
编辑方式就是直接打开上面生成的脚本,对你想要编辑的函数按以下格式编写:
#' Enhanced version of 'head'.
#' Default only print 5x5 field for two-dimensional data
#' or first 5 element for one-dimension data.
#' And print dimension of data in first line.
#' It also support specified range.
#' Don't worry about going out of range, it can fix it!
#'
#'
#' @title hd
#' @param obj data object.
#' @param x Number to print of horizontal direction, defaut 5.
#' @param y Number to print of vertical direction, defaut 5.
#' @author Jiahao Wang
#' @examples
#' hd(LETTERS, 10)
#' hd(LETTERS, 24:100)
#' df = get(data(package = "ggplot2", "diamonds"))
#' rownames(df) = paste0("row_", 1:nrow(df))
#' colnames(df) = paste0("col_", 1:ncol(df))
#' hd(df)
#' hd(df, 3, 5)
#' hd(df, 3:5, 7:9)
#' hd(df, -10:-nrow(df), -3:-5)
#' hd(df, (nrow(df) - 2):10^6, (ncol(df) - 2):10^6)
#' @return A part of input data.
#' @export
hd <- function(obj, x = 5, y = NULL){
check_len <- function(idx, max){
if(length(idx) > 1){
if(max(idx) > max){
idx_res = idx[idx <= max]
}else{
idx_res = idx
}
}else{
if(idx > max){
idx_res = 1:max
}else{
idx_res = 1:idx
}
}
return(idx_res)
}
if(is.null(y))
y = x
dims = is.null(dim(obj))
if(!dims){
cat("dim:", nrow(obj), "×", ncol(obj), "\n")
idx_x = check_len(x, nrow(obj))
idx_y = check_len(y, ncol(obj))
res = data.frame(obj[idx_x, idx_y])
if(!is.null(rownames(obj)))
rownames(res) = rownames(obj)[idx_x]
if(!is.null(colnames(obj)))
colnames(res) = colnames(obj)[idx_y]
} else{
cat("dim:", length(obj), "\n")
idx_x = check_len(x, length(obj))
res = obj[idx_x]
if(!is.null(names(obj)))
names(res) = names(obj)[idx_x]
}
return(res)
}
看起来就是这样:
![](https://img.haomeiwen.com/i5257017/ad42689b1bdf262f.png)
函数部分不用改动。
校验
为了生成R包,我们还需要进行格式校验、Rmd生成这两部,也是一键完成:
check()
document()
![](https://img.haomeiwen.com/i5257017/edd398a6b1d45ee7.png)
check的运行结果没用error就没问题,因为前面没用写依赖的包,所有提示了很多无法在当前环境找到该函数的定义
之类的信息,以后再解决这个问题。不影响使用,只是如果没用安装依赖包的话有些函数载入包时会提示报错。
生成并安装R包
setwd("../")
system(paste("Rcmd build", pkgName))
install_local(paste0(pkgName, "_", version, ".tar.gz"))
一切正常:
![](https://img.haomeiwen.com/i5257017/05ebd1dd9f900a09.png)
载入测试
library(efficeintR)
# 查看包介绍
packageDescription("efficeintR")
# 查看可用函数
ls("package:efficeintR")
- 看看刚才编写的
hd
函数:
?hd
有详细的文档说明
而没有编辑详细文档的:
?runWGCNA
![](https://img.haomeiwen.com/i5257017/606225c612ee0d68.png)
共享
直接分享压缩包或者上次到github使用devtools::install_github()
安装即可。
至此,一份香喷喷的R包制作完成~(品诺王语气
网友评论