最近我似乎和合作者分享了很多代码。他们中的许多人是新手/中级R用户,并没有意识到他们必须安装他们还没有的包。

是否有一种优雅的方式来调用installed.packages(),比较那些我正在加载和安装如果丢失?


当前回答

下面是我的代码:

packages <- c("dplyr", "gridBase", "gridExtra")
package_loader <- function(x){
    for (i in 1:length(x)){
        if (!identical((x[i], installed.packages()[x[i],1])){
            install.packages(x[i], dep = TRUE)
        } else {
            require(x[i], character.only = TRUE)
        }
    }
}
package_loader(packages)

其他回答

  packages_installed <- function(pkg_list){
        pkgs <- unlist(pkg_list)
        req <- unlist(lapply(pkgs, require, character.only = TRUE))
        not_installed <- pkgs[req == FALSE]
        lapply(not_installed, install.packages, 
               repos = "http://cran.r-project.org")# add lib.loc if needed
        lapply(pkgs, library, character.only = TRUE)
}

你可以使用find.package()。

这里几乎所有的答案都依赖于(1)require()或(2)installed.packages()来检查给定的包是否已经安装。

我添加了一个答案,因为这些对于回答这个问题的轻量级方法来说是不令人满意的。

Require具有加载包的名称空间的副作用,这可能并不总是可取的 安装。Packages是点燃蜡烛的火箭筒——它将首先检查所有已安装的包,然后我们检查这个库中是否有一个(或几个)包“库存”。没有必要为了找一根针而堆一堆干草堆。

这个答案也是受到@ArtemKlevtsov的启发,以类似的精神回答了这个问题的复制版本。他指出system.file(package=x)可以达到预期的效果,即返回“如果包未安装,则返回nchar > 1”。

如果我们深入了解系统。File实现了这个,我们可以看到它使用了不同的基函数find。包,我们可以直接使用:

# a package that exists
find.package('data.table', quiet=TRUE)
# [1] "/Library/Frameworks/R.framework/Versions/4.0/Resources/library/data.table"

# a package that does not
find.package('InstantaneousWorldPeace', quiet=TRUE)
# character(0)

我们还可以在find中查看引擎盖下的内容。包来看看它是如何工作的,但这主要是一个有指导意义的练习——我看到的唯一简化函数的方法是跳过一些健壮性检查。但是基本的想法是:在. libpaths()中查找——任何安装的包pkg将在file.path(. libpaths (), pkg)处有一个DESCRIPTION文件,因此快速检查file.exists(file.path(. libpaths (), pkg, 'DESCRIPTION')。

当前版本的RStudio(>=1.2)包含了一个功能,可以检测library()和require()调用中缺失的包,并提示用户安装它们:

检测丢失的R包 许多R脚本打开时调用library()和require()来加载执行所需的包。如果您打开一个R脚本,该脚本引用了您没有安装的包,RStudio现在将提供一次单击即可安装所有所需的包。不再重复输入install.packages(),直到错误消失! https://blog.rstudio.com/2018/11/19/rstudio-1-2-preview-the-little-things/

这似乎很好地解决了OP最初的问题:

他们中的许多人是新手/中级R用户,并没有意识到他们必须安装他们还没有的包。

上面的许多答案(以及这个问题的副本)依赖于安装。包装是不好的形式。从文档中可以看到:

当安装了数千个包时,这可能会很慢,所以不要使用它来查找是否安装了指定的包(使用system. exe)。或者查找一个包是否可用(调用require并检查返回值),或者查找少量包的详细信息(使用packageDescription)。每个安装的包需要读取几个文件,这在Windows和一些网络挂载的文件系统上会很慢。

因此,更好的方法是尝试使用require和install加载包,如果加载失败(如果没有找到require将返回FALSE)。我更喜欢这样的实现:

using<-function(...) {
    libs<-unlist(list(...))
    req<-unlist(lapply(libs,require,character.only=TRUE))
    need<-libs[req==FALSE]
    if(length(need)>0){ 
        install.packages(need)
        lapply(need,require,character.only=TRUE)
    }
}

可以这样使用:

using("RCurl","ggplot2","jsonlite","magrittr")

通过这种方式,它加载所有的包,然后返回并安装所有丢失的包(如果您愿意,可以在这里插入提示,询问用户是否想要安装包)。而不是调用install。对于每个包,它只传递一次卸载包的整个向量。

下面是相同的函数,但是有一个窗口对话框,询问用户是否想要安装缺少的包

using<-function(...) {
    libs<-unlist(list(...))
    req<-unlist(lapply(libs,require,character.only=TRUE))
    need<-libs[req==FALSE]
    n<-length(need)
    if(n>0){
        libsmsg<-if(n>2) paste(paste(need[1:(n-1)],collapse=", "),",",sep="") else need[1]
        print(libsmsg)
        if(n>1){
            libsmsg<-paste(libsmsg," and ", need[n],sep="")
        }
        libsmsg<-paste("The following packages could not be found: ",libsmsg,"\n\r\n\rInstall missing packages?",collapse="")
        if(winDialog(type = c("yesno"), libsmsg)=="YES"){       
            install.packages(need)
            lapply(need,require,character.only=TRUE)
        }
    }
}

达森·k和我有一个吃豆人包可以很好地做到这一点。包中的p_load函数执行此操作。第一行代码只是为了确保安装了pacman。

if (!require("pacman")) install.packages("pacman")
pacman::p_load(package1, package2, package_n)