最近我似乎和合作者分享了很多代码。他们中的许多人是新手/中级R用户,并没有意识到他们必须安装他们还没有的包。
是否有一种优雅的方式来调用installed.packages(),比较那些我正在加载和安装如果丢失?
最近我似乎和合作者分享了很多代码。他们中的许多人是新手/中级R用户,并没有意识到他们必须安装他们还没有的包。
是否有一种优雅的方式来调用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)。
其他回答
你可以使用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')。
library <- function(x){
x = toString(substitute(x))
if(!require(x,character.only=TRUE)){
install.packages(x)
base::library(x,character.only=TRUE)
}}
这适用于不带引号的包名,并且相当优雅(参见GeoObserver的答案)
此解决方案将获取包名的字符向量并尝试加载它们,或者在加载失败时安装它们。它依赖于require的返回行为来做到这一点,因为…
Require返回(不可见的)一个逻辑,指示所需的包是否可用
因此,我们可以简单地查看是否能够加载所需的包,如果不能,则使用依赖项安装它。所以给定一个你想要加载的包的字符向量…
foo <- function(x){
for( i in x ){
# require returns TRUE invisibly if it was able to load package
if( ! require( i , character.only = TRUE ) ){
# If package was not able to be loaded then re-install
install.packages( i , dependencies = TRUE )
# Load package after installing
require( i , character.only = TRUE )
}
}
}
# Then try/install packages...
foo( c("ggplot2" , "reshape2" , "data.table" ) )
使用packrat使共享库完全相同,而不会改变其他环境。
就优雅和最佳实践而言,我认为你从根本上走错了方向。打包程序就是为这些问题而设计的。它是由RStudio由Hadley Wickham开发的。packrat使用自己的目录,将您的程序的所有依赖项安装在其中,而不涉及别人的环境,这样他们就不必安装依赖项并可能弄乱别人的环境系统。
Packrat is a dependency management system for R. R package dependencies can be frustrating. Have you ever had to use trial-and-error to figure out what R packages you need to install to make someone else’s code work–and then been left with those packages globally installed forever, because now you’re not sure whether you need them? Have you ever updated a package to get code in one of your projects to work, only to find that the updated package makes code in another project stop working? We built packrat to solve these problems. Use packrat to make your R projects more: Isolated: Installing a new or updated package for one project won’t break your other projects, and vice versa. That’s because packrat gives each project its own private package library. Portable: Easily transport your projects from one computer to another, even across different platforms. Packrat makes it easy to install the packages your project depends on. Reproducible: Packrat records the exact package versions you depend on, and ensures those exact versions are the ones that get installed wherever you go.
https://rstudio.github.io/packrat/
这就是rbundler包的目的:提供一种方法来控制为特定项目安装的包。现在,这个包使用devtools功能将包安装到项目的目录中。该功能类似于Ruby的捆绑器。
如果你的项目是一个包(推荐),那么你所要做的就是加载rbundler并捆绑包。bundle函数将查看包的DESCRIPTION文件,以确定要捆绑哪些包。
library(rbundler)
bundle('.', repos="http://cran.us.r-project.org")
现在这些包将安装在. rbundle目录中。
如果你的项目不是一个包,那么你可以在项目的根目录中创建一个DESCRIPTION文件,其中包含一个Depends字段,列出你想要安装的包(包括可选的版本信息):
Depends: ggplot2 (>= 0.9.2), arm, glmnet
如果你对这个项目感兴趣,这里是github回购:rbundler。