如何在 R 包中的函数之前加载内部存储的数据?

问题描述 投票:0回答:1

我目前正在为我的合作者编写一个包含特定于项目的数据清理功能的 R 包,使用 devtools 和 roxygen2 并遵循 RStudio 建议的格式。其中许多函数本质上是使用当前存储在 /R 下的包的 sysdata.rda 文件中的参考文件(数据帧)来修复拼写错误/常见数据输入错误。在我提出下面的问题之前,引用文件并在函数中使用它们工作得很好。延迟加载设置为 true。

我想创建一个功能,允许用户在遇到新的拼写错误/错误时向这些参考文件添加一行。根据我的研究和阅读https://r-pkgs.org/data.html上非常有用的信息,似乎最好的方法是将参考文件列出到新环境,然后允许用户在特定于会话的环境中编辑这些文件。理想情况下,这些更改将在整个会话中持续存在,但我不知道如何实现这一点,所以我继续沿着这条路走下去。

为了简洁起见,我只包含了其中一个文件,名为 column_standardized,其中包含列的标准名称以及我们经常遇到的潜在替代方案。一个名为“standardize.columns”的函数将输入数据帧的列名称强制为标准,并将它们重新排序为我们商定的标准。

这是列标准化的简短重现:

column_standardized <- data.frame(standard_name = c("date", "date", "time", "ID", "ID", "ID", "location", "location"), other_names = c("DATE", "day", "TIME", "id", "individual", "name", "LOCATION", "locale"))

为此,我在 /R 中创建了一个文件,其中包含以下代码,很大程度上基于 https://r-pkgs.org/data.html 中的示例(第 8.5 节,内部状态)。该文件的标题为“aaaaa.R”,因此它位于 /R 中的其他函数之前: (我设置 key、 Correct_col 和 alt_col 的原因是,相同的函数可以使用相同的代码作用于不同的参考文件。它工作得很好,我不一定要寻求有关该函数的数据操作方面的反馈。)

the <- new.env(parent = emptyenv())
the$column_standardized <- column_standardized

#' Add alternative names to reference
#'
#' @param correct A character string of the standard/correct name
#' @param alt A character string of the alternative name
#' @param data_type A character string indicating which reference file to edit. Options are 'column' (and others in reality).
#'
#' @return NA; edits included reference files for current R session.
#' @export
add.alt <- function(correct, alt, data_type){
  if(data_type == "column"){
    key <- the$column_standardized
    correct_col <- "standard_name"
    alt_col <- "other_names"
  }else{print("\nData type not found. Acceptable options are 'column', etc.")}
  new_key <- data.frame(matrix(ncol = length(colnames(key)), nrow = 1))
  colnames(new_key) <- colnames(key)
  new_key[1,correct_col] <- correct
  new_key[1, alt_col] <- alt
  key <- rbind(key, new_key)
  if(data_type == "column"){
    the$column_standardized <- key
    invisible(key)
  }}

当我运行 document() 或 load_all() 时,没有标记任何错误/问题,但是当我检查包时,它无法安装,因为 column_standardized 不存在。我认为这是因为 sysdata.rda 在 /R 中的 .R 文件之后加载。

我还尝试将 column_standardized 放在 /data 文件夹中并使用 system.file 调用它,但遇到了相同的错误。

实际文件超过 300 行长,并且有多个参考文件,因此我认为从头开始在环境中重新创建数据框是没有意义的,尽管我已经考虑过。

最后,针对我的具体问题:

  1. 有没有办法先加载系统数据,以便/R中的.R文件可以引用包含的数据?
  • 我不打算在内部存储它们,尽管出于隐私原因这将是理想的选择,并且可以将数据帧移动到 /data 或其他位置。这最初看起来很简单,但我可能是错的。
  1. 是否有修改允许每个用户“永久”修改这些参考文件?对于他们来说,在每个会话中运行 add.alt() 不会太令人头疼,因为文件已经包含最常见的错误,并且一旦用户数据被编辑/标准化,通常不需要在另一个会话中重新标准化。然而,如果有人知道解决方案,它可能是理想的解决方案。

我可能完全偏离了基地,因为这是我第一次开发软件包,所以任何提示都值得赞赏!提前非常感谢,如果我忘记了任何重要的内容,很乐意提供更多文档信息。

r package devtools roxygen2
1个回答
0
投票

对于遇到此问题/想要以这种方式在 R 包中包含可编辑数据的其他人,我在下面详细介绍了对该问题的修复。非常感谢上面的评论者链接到那个有用的博客。

所有参考文件都存储在/R下的sysdata.Rda文件中。包中的两个函数将基线参考文件写入用户的 R 数据缓存,并在每个新的 R 会话时从该缓存中提取文件。

安装后,用户将被引导运行 save.reference(dir.create = TRUE) 将所有参考文件写入其用户缓存:

function (file = "all", dir.create = FALSE) 
{
    if (dir.create == TRUE) {
        dir.create(tools::R_user_dir("packagename", which = "cache"), 
            recursive = TRUE)
    }
    path <- paste(tools::R_user_dir("packagename", which = "cache"))
    if (file == "all") {
        file <- c("file 1", "file 2", 
            "file 3", "etc")
    }
    for (filename in file) {
        utils::write.csv(get(filename), paste(path, "/", filename, 
            ".csv", sep = ""), row.names = FALSE)
    }
}

然后,load.reference()从缓存中读取任意或所有参考文件到当前的R环境中:

function (file = "all") 
{
    path <- paste(tools::R_user_dir("packagename", which = "cache"))
    if (file == "all") {
        file <- c("file 1", "file 2", 
            "file 3", "etc")
    }
    for (filename in file) {
        temp <- utils::read.csv(paste(path, "/", filename, ".csv", 
            sep = ""))
        print2envlist <- list(temp = temp)
        names(print2envlist)[1] <- filename
        list2env(print2envlist, .GlobalEnv)
    }
}

在 R 会话期间所做的任何更改都可以在退出之前通过运行 save.reference() 进行保存。如果需要对任何参考文件进行长期的、用户范围内的更改,可以将它们包含在包更新中,然后可以通过再次运行 save.reference(dir.create = TRUE) 来覆盖用户文件。用户还可以在缓存位置访问文件资源管理器中的文件,并在任何其他程序中编辑它们。

如果其他人发现自己处于同样的情况,我希望这会有所帮助!

© www.soinside.com 2019 - 2024. All rights reserved.