最近我似乎和合作者分享了很多代码。他们中的许多人是新手/中级R用户,并没有意识到他们必须安装他们还没有的包。
是否有一种优雅的方式来调用installed.packages(),比较那些我正在加载和安装如果丢失?
最近我似乎和合作者分享了很多代码。他们中的许多人是新手/中级R用户,并没有意识到他们必须安装他们还没有的包。
是否有一种优雅的方式来调用installed.packages(),比较那些我正在加载和安装如果丢失?
当前回答
您可以简单地使用setdiff函数获取未安装的包,然后安装它们。在下面的示例中,我们在安装ggplot2和Rcpp包之前检查它们是否已经安装。
unavailable <- setdiff(c("ggplot2", "Rcpp"), rownames(installed.packages()))
install.packages(unavailable)
在一行中,上面的内容可以写成:
install.packages(setdiff(c("ggplot2", "Rcpp"), rownames(installed.packages())))
其他回答
在我的例子中,我想要一个可以从命令行(实际上是通过Makefile)运行的一行程序。下面是一个安装“VGAM”和“feather”的例子,如果它们还没有安装:
R -e 'for (p in c("VGAM", "feather")) if (!require(p, character.only=TRUE)) install.packages(p, repos="http://cran.us.r-project.org")'
在R内部,它就是:
for (p in c("VGAM", "feather")) if (!require(p, character.only=TRUE)) install.packages(p, repos="http://cran.us.r-project.org")
除了前面的解之外,这里没有别的解:
我只说一句 我硬编码回购参数(以避免任何弹出窗口询问使用的镜像) 我不想费心定义一个在其他地方使用的函数
还要注意重要的字符。only=TRUE(如果没有它,require将尝试加载包p)。
下面是我的代码:
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)
有一个新的包(我是一个联合开发人员),Require,它是可复制工作流的一部分,这意味着函数在第一次运行或后续运行时产生相同的输出,也就是说,无论开始状态如何,最终状态都是相同的。下面安装任何缺失的包(我包含require = FALSE以严格解决最初的问题…通常我把这个设置为默认值,因为我通常希望它们加载到搜索路径)。
这两行位于我编写的每个脚本的顶部(根据需要调整包的选择),允许任何人在任何条件下(包括任何或所有依赖项缺失)使用脚本。
if (!require("Require")) install.packages("Require")
Require::Require(c("ggplot2", "Rcpp"), require = FALSE)
因此,您可以在脚本中使用它或将其传递给任何人。
library <- function(x){
x = toString(substitute(x))
if(!require(x,character.only=TRUE)){
install.packages(x)
base::library(x,character.only=TRUE)
}}
这适用于不带引号的包名,并且相当优雅(参见GeoObserver的答案)
你可以使用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')。