在编写 R 包时,烘焙一些数据集通常是一种很好的做法,通常用于教育/教程目的。 Hadley Wickham 关于 R 包的书中有一章介绍了这一点:https://r-pkgs.org/data.html
我有一个用例,其中有几个数据集我也想通过包提供,但它们实际上是远程的。我经常使用 {dbplyr} 并编写大量 R 代码来与我的数据库交互,但就其本质而言,它们必须是远程的。
所以,我经常做类似的事情
production <- DBI::dbConnect(
RPostgres::Postgres(),
host = Sys.getenv("POSTGRES_SERVER"),
dbname = Sys.getenv("PRODUCTION_DATABASE"),
user = Sys.getenv("POSTGRES_USER"),
password = Sys.getenv("POSTGRES_PASSWORD")
)
my_table <- dplyr::tbl(production, dbplyr::in_schema("our_database", "my_table"))
head(my_table)
是否可以在我的自定义 R 包中包含这样的内容:
head(my_pkg::my_table)
据我所知,哈德利的书中并没有真正涉及这个案例。 也许第 7.2 节 - 内部数据?
如何最好地解决这个问题取决于数据的敏感性、目标受众以及您想要提供信息的目的。以下是您可以尝试的四种不同方法。
在每种情况下,我都将它们编写为
demo_function
,您的用户在熟悉您的包时可能会调用它们。我假设您可能会将这些内容包含在小插图或文档中。
请注意,要将数据包含在 GitHub 存储库中,文件大小有限制。
dbplyr 包含用于模拟数据库连接的选项。
demo_function = function(){
data(starwars)
# simulated connection
remote_df = tbl_lazy(starwars, con = simulate_postgres())
# computation
out = mutate(remote_df, substring_col = grepl("Luke", name)))
return(out)
}
SQLite 在 R 中可用。您可以在包的 extdata 文件夹中包含 SQLite 数据库文件。
软件包开发期间的设置:
path = system.file("extdata", "testing", package = "my.new.package")
db_path = file.path(path, "testing_sqlite.db")
db_conn = DBI::dbConnect(RSQLite::SQLite(), db_path)
# add table
data(iris)
DBI::dbWriteTable(db_conn, "iris_table", iris)
用途:
demo_function = function(){
path = system.file("extdata", "testing", package = "my.new.package")
db_path = file.path(path, "testing_sqlite.db")
db_conn = DBI::dbConnect(RSQLite::SQLite(), db_path)
my_table = dplyr::tbl(db_conn, "iris")
return(my_table)
}
您可以编写一个演示 R 文件,供用户自定义以进行自己的分析。
脚本保存到extdata:
# INSTRUCTIONS:
# Edit the lines of this file to provide the required connection details.
production <- DBI::dbConnect(
RPostgres::Postgres(),
host = Sys.getenv("POSTGRES_SERVER"),
dbname = Sys.getenv("PRODUCTION_DATABASE"),
user = Sys.getenv("POSTGRES_USER"),
password = Sys.getenv("POSTGRES_PASSWORD")
)
my_table <- dplyr::tbl(production, dbplyr::in_schema("our_database", "my_table"))
head(my_table)
辅助功能:
demo_function = function(){
folder = getwd()
# locations
to_dir = file.path(normalizePath(folder), "demo_script")
from_dir = system.file("extdata", "demo_script", package = "my.new.package")
# copy
file.copy(
list.files(from_dir, full.names = TRUE),
to_dir,
recursive = TRUE
)
}
您可以将凭据保存在不属于包的单独文件中。该文件可以与包一起提供给内部用户。当包运行时,如果发现错误/警告/提示(您的选择),它将使用凭证文件。
demo_function = function(host = NULL, dbname = NULL, user = NULL, password = NULL, db = NULL){
# load credential file if exists
credentials = "C:/expected/folder/credential_file.txt"
if(file.exists(credentials)){
con = file(credentials, "r")
host = readLines(con, n = 1)
dbname = readLines(con, n = 1)
user = readLines(con, n = 1)
password = readLines(con, n = 1)
close(con)
}
# prompt if NULL
if(is.null(host)){
host = readline("What is the value of host?")
}
if(is.null(dbname)){
dbname = readline("What is the value of dbname?")
}
if(is.null(user)){
user = readline("What is the value of user?")
}
if(is.null(password)){
password = readline("What is the value of password?")
}
# return connection
production <- DBI::dbConnect(
RPostgres::Postgres(),
host = host,
dbname = dbname,
user = user,
password = password
)
}