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

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


当前回答

你可以使用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')。

其他回答

if (!require('ggplot2')) install.packages('ggplot2'); library('ggplot2')

“ggplot2”是包。它检查包是否安装,如果没有安装,就安装它。然后不管它采用哪个分支,它都会加载包。

当前版本的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用户,并没有意识到他们必须安装他们还没有的包。

是的。如果您有软件包列表,请将其与installed.packages()[,"Package"]的输出进行比较,然后安装缺少的软件包。就像这样:

list.of.packages <- c("ggplot2", "Rcpp")
new.packages <- list.of.packages[!(list.of.packages %in% installed.packages()[,"Package"])]
if(length(new.packages)) install.packages(new.packages)

否则:

如果您将代码放在包中并使它们成为依赖项,那么当您安装包时,它们将自动安装。

你可以使用require的返回值:

if(!require(somepackage)){
    install.packages("somepackage")
    library(somepackage)
}

我在安装后使用library,因为如果安装不成功或由于其他原因无法加载包,它将抛出异常。您可以使其更加健壮和可重用:

dynamic_require <- function(package){
  if(eval(parse(text=paste("require(",package,")")))) return(TRUE)
  
  install.packages(package)
  return(eval(parse(text=paste("require(",package,")"))))
}

此方法的缺点是必须以引号传递包名,而对于真正的require则不这样做。

有一个新的包(我是一个联合开发人员),Require,它是可复制工作流的一部分,这意味着函数在第一次运行或后续运行时产生相同的输出,也就是说,无论开始状态如何,最终状态都是相同的。下面安装任何缺失的包(我包含require = FALSE以严格解决最初的问题…通常我把这个设置为默认值,因为我通常希望它们加载到搜索路径)。

这两行位于我编写的每个脚本的顶部(根据需要调整包的选择),允许任何人在任何条件下(包括任何或所有依赖项缺失)使用脚本。

if (!require("Require")) install.packages("Require")
Require::Require(c("ggplot2", "Rcpp"), require = FALSE)

因此,您可以在脚本中使用它或将其传递给任何人。