如何判断你在 R 中使用了哪些包

Posted

技术标签:

【中文标题】如何判断你在 R 中使用了哪些包【英文标题】:How to tell what packages you have used in R 【发布时间】:2015-04-15 07:29:32 【问题描述】:

我有一个很长的 R 脚本,其中包含许多 if 语句和异常情况。正如我一直在做的那样,如果我一直在导入和测试库,并且还没有真正很好地记录它们。问题是,如果我从全新安装运行它,我不确定脚本将运行哪些语句,以及需要哪些库。

我的问题是:是否有任何 R 函数来测试脚本中正在使用哪些库?

编辑:我没有使用所有已安装的库,所以 print(sessionInfo()) 不会有用,但我只想用 install.packages 函数启动脚本

【问题讨论】:

this is what are you looking for @Ethaan 这不是他真正要问的 我认为您正在寻找脚本作者的铲除/中性工具。我认为你注定要运行脚本并安装包,弄清楚哪个函数来自哪个包。祝你在不同包中使用相同名称的函数好运(这是该工具派上用场的地方)。我发现library("sos");findFn("foo") 可以方便地查找函数。 @Ethaan 不用担心,它实际上也可以是一个有用的链接! 我认为应该接受eh21的回答。 【参考方案1】:

我不确定自动执行此操作的好方法...但您可以做的是:

    打开一个新的 R 控制台

    请与sessionInfo 确认您没有加载额外的包。 您可以使用sessionInfo 进行检查。如果您默认加载额外的包(例如,使用您的 .RProfile 文件),我建议您避免这样做,因为这会导致灾难。 通常你应该只加载基本包:statsgraphicsgrDevicesutilsdatasetsmethodsbase

    您可以使用以下方法卸载任何额外的库:

    detach("package:<packageName>", unload=TRUE)
    

    现在在注释所有 libraryrequire 调用后运行脚本,看看哪些函数会出错。

    在控制台中获取每个函数类型需要哪个包:

    ??<functionName>
    

    加载所需的包并重新运行步骤 3-5,直到满意为止。

【讨论】:

是的,这就是我目前正在做的事情。在开始安装我目前下载的所有软件包时,我可能只会有一些声明。 - 即使它们没有用。【参考方案2】:

您可能想在 GitHub 上查看来自 Revolution Analytics 的检查点功能:https://github.com/RevolutionAnalytics/checkpoint

它做了一些这样的事情,并解决了可重复性的问题。但我不认为它可以报告您正在使用的列表。

但是,如果您查看代码,您可能会得到一些想法。

【讨论】:

【参考方案3】:

如今,“renv”包通过renv::dependencies为此提供了强大的解决方案。

renv::dependencies 执行适当的静态分析并可靠地找到包依赖关系,即使它们以非标准方式(例如通过box::use)或通过包DESCRIPTION 文件而不是通过library:: 声明.


作为一个快速破解,我之前(pre-'renv')为此使用了a shell script:

#!/usr/bin/env bash

source_files=($(git ls-files '*.R'))
grep -hE '\b(require|library)\([\.a-zA-Z0-9]*\)' "$source_files[@]" | \
    sed '/^[[:space:]]*#/d' | \
    sed -E 's/.*\(([\.a-zA-Z0-9]*)\).*/\1/' | \
    sort -uf \
    > DEPENDS

这使用 Git 来收集项目中版本控制下的所有 R 文件。因为您无论如何都应该使用版本控制,这通常是一个很好的解决方案(尽管您可能想要调整版本控制系统)。对于项目不受版本控制的少数情况,您应该 (1) 将其置于版本控制之下。或者,如果做不到这一点,(2)使用find . -regex '.*\.[rR]' 而不是git ls-files '*.R'

它会生成一个DEPENDS file,其中包含一个非常简单的依赖项列表。

不过,它只能找到对 libraryrequire 的直接调用——如果你包装这些调用,脚本将无法工作。

【讨论】:

我不认为 OP 要求这个,但我可能误解了这个问题。我想他要问的是:他已经加载了几个库,不确定哪个是不必要的。 如果您使用 [\.a-ZA-Z0-9] 而不是 \w[[:alnum:]],您将捕获所有有效的 R 包名称。 这很棒。我们能以某种方式将其放入usethis 吗? (此外,它目前不处理未附加但由::::: 访问的要求,adv-r.had.co.nz/Expressions.html#ast-funs 可能是更通用的基于 R 的实施的良好起点)再说一次,我想我应该使用 roxygen ... @jan-glx 老实说,我今天不会使用这个 sn-p。如果我必须自己实现这个,我会做一个适当的静态分析,可能基于“codetools”包。也就是说,'renv' 已经实现了这一点,并且做得好多,因为它还支持声明包依赖项的非标准方式(例如通过box::use)。我已更新我的答案以反映这一点。【参考方案4】:

当我需要将我的代码转换为一个包时,我也有类似的需求,因此我需要识别每个包依赖项并导入或使用完整的限定名。

在看书Extending R我发现XRtools::makeImports可以扫描一个包,发现所有需要导入的包。这还不能解决我们的问题,因为它只适用于现有的包,但它提供了关于如何做到这一点的主要见解。

我做了一个函数并将它放入我的包mischelper。您可以安装软件包,使用 RStudio 插件菜单扫描当前文件或选定代码,或使用命令行功能。每个外部函数(fun_inside)和调用它的函数(用法)都会列在表中。

您现在可以转到每个功能,按 F1 查找它属于哪个包。我实际上还有另一个包,它可以扫描所有已安装包的函数名称并构建数据库,但这可能会导致更多误报,因为如果您只加载了一些包,按 F1 只会搜索已加载的包。

在我的包页面查看使用详情

https://github.com/dracodoc/mischelper

【讨论】:

【参考方案5】:

我发现 NCmisc (install.packages("NCmisc")) 的 list.functions.in.file() 函数对此非常有帮助:

list.functions.in.file(filename, alphabetic = TRUE)

欲了解更多信息,请参阅此链接:https://rdrr.io/cran/NCmisc/man/list.functions.in.file.html

【讨论】:

为什么这被否决了?这不是首选选项有什么原因吗? 请注意——你需要先加载包,否则NCmisc不知道函数来自哪个包。 如果你在使用 RStudio 并且想用它来检查你打开的脚本,运行list.functions.in.file(rstudioapi::getSourceEditorContext()$path, alphabetic = TRUE) 这种方法的一个问题是它实际上并没有关注包的加载顺序,所以它会显示函数来自多个包,而在脚本的现实中它会是来自一个特定的。你知道任何可以更好地解决这个问题的替代方案吗? 我写了一个包 funspotr,它本质上是 list.functions.in.file,但以数据框格式输出内容并进行一些其他小的更改:github.com/brshallo/funspotr【参考方案6】:

根据大家的反应,尤其是eh21对NCmisc包的建议,我整理了一个小函数,输出一个目录中所有R脚本中使用的包的列表,以及它们的频率。

library(NCmisc)
library(stringr)
library(dplyr)

checkPacks<-function(path)

    ## get all R files in your directory
    ## by the way, extract R code from Rmd: http://felixfan.github.io/extract-r-code/
    files<-list.files(path)[str_detect(list.files(path), ".R$")]

    ## extract all functions and which package they are from 
    ## using NCmisc::list.functions.in.file
    funs<-unlist(lapply(paste0(path, "/", files), list.functions.in.file))
    packs<-funs %>% names()

    ## "character" functions such as reactive objects in Shiny
    characters<-packs[str_detect(packs, "^character")]

    ## user defined functions in the global environment
    globals<-packs[str_detect(packs, "^.GlobalEnv")]

    ## functions that are in multiple packages' namespaces 
    multipackages<-packs[str_detect(packs, ", ")]

    ## get just the unique package names from multipackages
    mpackages<-multipackages %>%
               str_extract_all(., "[a-zA-Z0-9]+") %>%
               unlist() %>%
               unique()
    mpackages<-mpackages[!mpackages %in% c("c", "package")]

    ## functions that are from single packages
    packages<-packs[str_detect(packs, "package:") & !packs %in% multipackages] %>%
              str_replace(., "[0-9]+$", "") %>%
              str_replace(., "package:", "") 

    ## unique packages
    packages_u<-packages %>%
                unique() %>%
                union(., mpackages)

    return(list(packs=packages_u, tb=table(packages)))



checkPacks("~/your/path")

【讨论】:

Nice 很好用,但它只检查加载的库。一种解决方案是加载此博客文章中描述的所有已安装包:r-bloggers.com/loading-all-installed-r-packages 短:lapply(.packages(all.available = TRUE), function(xx) library(xx, character.only = TRUE)) 很好,但你应该让第一个 list.files-call 中的正则表达式为 ".R$|.r$" 以便也使用带有 .r 的文件(像我一样 - 我从不使用与编程相关的文件夹中的大写字母。 您也可以使用正则表达式的模式参数而不是字符串,如下所示: 文件 【参考方案7】:

我最信任基于 renv 的解决方案来识别包依赖关系。

虽然我编写了一个包funspotr,其中包含与提到NCmisc::list.functions.in.file() 的答案类似的功能,并且可用于解析一个或多个文件中的函数或包:

library(dplyr)

funspotr::spot_pkgs("https://gist.githubusercontent.com/brshallo/4b8c81bc1283a9c28876f38a7ad7c517/raw/b399b768e900a381d99f5120e44d119c7fb40ab9/source_rmd.R")
#> [1] "knitr"    "magrittr" "stringr"  "readr"    "purrr"    "glue"

funspotr::spot_funs("https://gist.githubusercontent.com/brshallo/4b8c81bc1283a9c28876f38a7ad7c517/raw/b399b768e900a381d99f5120e44d119c7fb40ab9/source_rmd.R") %>% 
  select(-in_multiple_pkgs)
#> # A tibble: 13 x 2
#>    funs        pkgs   
#>    <chr>       <chr>  
#>  1 tempfile    base   
#>  2 purl        knitr  
#>  3 getOption   base   
#>  4 options     base   
#>  5 .Call       base   
#>  6 source      base   
#>  7 library     base   
#>  8 read_file   readr  
#>  9 map         purrr  
#> 10 str_extract stringr
#> 11 glue        glue   
#> 12 str_c       stringr
#> 13 write_file  readr

【讨论】:

以上是关于如何判断你在 R 中使用了哪些包的主要内容,如果未能解决你的问题,请参考以下文章

如何运行使用旧版本包和最新 R 版本和包中的 R 编写的 R 脚本? [关闭]

如何查找哪些列会影响 R 中的预测

使用 R 中的 SP 包查找哪些多边形包含哪些点时遇到问题

使用TCP协议批量扫描端口

java:从外面导入一个jdom包,使用这个包里面的类,还想看这个类都有哪些方法,怎么看?

Linux新手需要掌握哪些管理器?