检查缺失的软件包并安装它们的优雅方式?

Elegant way to check for missing packages and install them?

提问人:Maiasaura 提问时间:11/4/2010 最后编辑:JaapMaiasaura 更新时间:9/5/2023 访问量:240678

问:

这些天来,我似乎与合著者共享了很多代码。他们中的许多人是新手/中级 R 用户,他们没有意识到他们必须安装他们还没有的包。

有没有一种优雅的调用方式,将其与我正在加载和安装的那些进行比较(如果丢失)?installed.packages()

R-FAQ

评论

1赞 Brian Diggs 11/8/2013
@krlmlr 接受的答案已过期并需要修改怎么办?它对我有用(用于一些快速测试)。R version 3.0.2 (2013-09-25) x86_64-w64-mingw32/x64 (64-bit)
1赞 krlmlr 11/8/2013
@BrianDiggs:至少出现了三个解决此问题的软件包,下面只引用了一个。还有更多吗--这就是问题所在。
3赞 Brian Diggs 11/8/2013
@krlmlr 关于使用软件包来确保(其他人)拥有必要的软件包,似乎存在一些具有讽刺意味的先有鸡还是先有蛋的问题。但当然值得让了解他们的人写一个答案。
2赞 krlmlr 11/8/2013
@BrianDiggs:引导这个安装检查包是必要的麻烦,但很小。当然,除非该功能进入...... ;-)base
1赞 mel 5/25/2021
来自 Node.js,这是多么难。这怎么不是语言的第一类功能?

答:

405赞 Shane 11/4/2010 #1

是的。如果您有软件包列表,请将其与 的输出进行比较,并安装缺少的软件包。像这样的东西: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)

否则:

如果将代码放在包中并使其成为依赖项,则在安装包时会自动安装它们。

评论

16赞 8/14/2015
我认为正确的语法是:if(length(new.packages)>0) {install.packages(new.packages)}
8赞 Andrea Cirillo 1/22/2016
@psql,Shine 是对的,因为“>0”在 if 条件中是“隐式”的。运行以下命令以验证它:new.packages <- c(1,2) length(new.packages) if(length(new.packages)){print("hello!")}else{print("oh no!")}
9赞 Thomas Materna 5/11/2016
installed.packages 的文档指出:“当安装了数千个软件包时,这可能会很慢,因此不要使用它来确定是否安装了命名软件包(使用 system.file 或 find.package)...”
2赞 Matthew 6/21/2017
同意托马斯的观点,这将是更好的性能,而不是检查requireinstalled.packages
1赞 mtelesha 11/3/2017
packrat就是为此而生的。它是一个可复制的包管理系统。这种方式是以错误的方式进行,并扰乱了别人的环境并且不可复制。Packrat 有自己的共享库文件夹和环境。rstudio.github.io/packrat
6赞 Dirk is no longer here 11/4/2010 #2

确定。

您需要将“已安装的软件包”与“所需的软件包”进行比较。这与我对 CRANberries 所做的非常接近,因为我需要将“存储的已知包”与“当前已知包”进行比较,以确定新的和/或更新的包。

所以做一些事情,比如

AP <- available.packages(contrib.url(repos[i,"url"]))   # available t repos[i]

若要获取所有已知包,请模拟调用当前安装的包,并将其与一组给定的目标包进行比较。

16赞 Juan Antonio Cano 1/15/2012 #3

虽然 Shane 的回答非常好,但对于我的一个项目,我需要自动删除输出消息、警告和安装包。我终于设法得到了这个脚本:

InstalledPackage <- function(package) 
{
    available <- suppressMessages(suppressWarnings(sapply(package, require, quietly = TRUE, character.only = TRUE, warn.conflicts = FALSE)))
    missing <- package[!available]
    if (length(missing) > 0) return(FALSE)
    return(TRUE)
}

CRANChoosen <- function()
{
    return(getOption("repos")["CRAN"] != "@CRAN@")
}

UsePackage <- function(package, defaultCRANmirror = "http://cran.at.r-project.org") 
{
    if(!InstalledPackage(package))
    {
        if(!CRANChoosen())
        {       
            chooseCRANmirror()
            if(!CRANChoosen())
            {
                options(repos = c(CRAN = defaultCRANmirror))
            }
        }

        suppressMessages(suppressWarnings(install.packages(package)))
        if(!InstalledPackage(package)) return(FALSE)
    }
    return(TRUE)
}

用:

libraries <- c("ReadImages", "ggplot2")
for(library in libraries) 
{ 
    if(!UsePackage(library))
    {
        stop("Error!", library)
    }
}
1赞 metasequoia 12/2/2012 #4

我使用以下命令来检查是否安装了包以及是否更新了依赖项,然后加载包。

p<-c('ggplot2','Rcpp')
install_package<-function(pack)
{if(!(pack %in% row.names(installed.packages())))
{
  update.packages(ask=F)
  install.packages(pack,dependencies=T)
}
 require(pack,character.only=TRUE)
}
for(pack in p) {install_package(pack)}

completeFun <- function(data, desiredCols) {
  completeVec <- complete.cases(data[, desiredCols])
  return(data[completeVec, ])
}
7赞 Erik Shilts 12/3/2012 #5

这就是 rbundler 软件包的目的:提供一种方法来控制为特定项目安装的软件包。现在,该包与 devtools 功能配合使用,可将包安装到项目的目录中。其功能类似于 Ruby 的打包器

如果你的项目是一个包(推荐),那么你所要做的就是加载 rbundler 并捆绑包。该函数将查看包的文件,以确定要捆绑哪些包。bundleDESCRIPTION

library(rbundler)
bundle('.', repos="http://cran.us.r-project.org")

Now the packages will be installed in the .Rbundle directory.

If your project isn't a package, then you can fake it by creating a file in your project's root directory with a Depends field that lists the packages that you want installed (with optional version information):DESCRIPTION

Depends: ggplot2 (>= 0.9.2), arm, glmnet

Here's the github repo for the project if you're interested in contributing: rbundler.

24赞 Simon O'Hanlon 11/9/2013 #6

This solution will take a character vector of package names and attempt to load them, or install them if loading fails. It relies on the return behaviour of to do this because...require

require returns (invisibly) a logical indicating whether the required package is available

Therefore we can simply see if we were able to load the required package and if not, install it with dependencies. So given a character vector of packages you wish to load...

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" ) )

评论

0赞 krlmlr 11/9/2013
Wouldn't you want to call again after installing?require
0赞 Simon O'Hanlon 11/9/2013
@krlmlr Nope, because in order for the statement to be evaluated it must first evaluate , the side-effect of which is loading the package if it is available!ifrequire
1赞 Aaron left Stack Overflow 11/9/2013
SimonO101: I think krlmlr means in the if statement, after the call to , as this wouldn't actually load that package. But (to @krlmlr) I suspect the intent is that this code fragment would only be called once; you wouldn't write this every time you required the package. Instead you'd run it once ahead of time and then call as usual as needed.install.packagesrequire
0赞 Simon O'Hanlon 11/9/2013
@Aaron ah yes ok, I see what you mean, and yes your interpretation is correct. I'll edit it slightly to be more explicit about loading after installing.
1赞 kabdulla 11/10/2016
wouldn't it be better to make the second a call to so that it fails noisily if it is still unable to attach the package for some reason?requirelibrary
91赞 Livius 11/9/2013 #7

You can just use the return value of :require

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

I use after the install because it will throw an exception if the install wasn't successful or the package can't be loaded for some other reason. You make this more robust and reuseable:library

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

The downside to this method is that you have to pass the package name in quotes, which you don't do for the real .require

评论

7赞 Simon O'Hanlon 11/9/2013
You can simplify your life a lot by using in , but then I guess there is nothing to differentiate your answer from mine.character.only = TRUErequire
0赞 Dr. Fabian Habersack 7/13/2019
This looks nice but it doesn't seem to work, at least for me. When I tried the robust version of this, I get two error messages as R doesn't know how to handle "return True" and "return eval" for some reason. So I would really like a function like this that loads a package if present in my library and otherwise installs (and afterwards loads) the package. Ideally I would then use this as a default to load packages. At least it seems it would make sense to do so and would save some time.
315赞 Tyler Rinker 11/9/2013 #8

Dason K. and I have the pacman package that can do this nicely. The function in the package does this. The first line is just to ensure that pacman is installed.p_load

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

评论

1赞 MERose 2/5/2015
What's the status of the package? I can't see in on C-RAN.
4赞 Tyler Rinker 2/18/2015
@MERose pacman is now on CRAN cran.r-project.org/web/packages/pacman/index.html
6赞 Andi F 9/16/2015
Have installed now and works wonderfully; should be part of base!
3赞 airstrike 6/9/2016
The only way this would be better would be if it checked for and, if found, install/load from github automatically./
4赞 Tyler Rinker 5/25/2018
@NealBarsch if you mean the there's a function in pacman called that maks this line for you automagically and copies it to the clipboard.if (!require("pacman")) install.packages("pacman")p_boot()
2赞 GeoObserver 11/12/2013 #9

关于您的主要目标“安装他们还没有的库”,并且无论是否使用“ instllaed.packages() ”。以下函数掩盖了 require 的原始函数。它尝试加载并检查命名包“x”,如果没有安装,则直接安装它,包括依赖项;最后正常加载它。将函数名称从“require”重命名为“library”以保持完整性。唯一的限制是软件包名称应使用引号。

require <- function(x) { 
  if (!base::require(x, character.only = TRUE)) {
  install.packages(x, dep = TRUE) ; 
  base::require(x, character.only = TRUE)
  } 
}

因此,您可以按照 R 的老式方式加载和安装包。 要求 (“ggplot2”) 要求 (“Rcpp”)

评论

0赞 Michael Petrotta 11/17/2013
如果您不再喜欢您的答案,请不要破坏它 - 只需删除它即可。
0赞 GeoObserver 11/18/2013
好吧,我试过了,但我做不到。我认为我的 FF 的 NoScript 扩展正在禁用它,或者我没有权利和信用来删除我自己的答案。LoL 但是,我认为 Livius 非常接近我的答案,没有掩饰地思考。谢谢迈克尔·佩特罗塔。用于通知。
0赞 Michael Petrotta 11/19/2013
您应该在这些评论上方看到一个链接。如果您不这样做,但仍想删除,请使用链接,选择“其他”,然后向版主说明您希望删除答案。deleteflag
15赞 Brian Spiering 2/16/2014 #10
# List of packages for session
.packages = c("ggplot2", "plyr", "rms")

# Install CRAN packages (if not already installed)
.inst <- .packages %in% installed.packages()
if(length(.packages[!.inst]) > 0) install.packages(.packages[!.inst])

# Load packages into session 
lapply(.packages, require, character.only=TRUE)

评论

2赞 mikey 7/31/2021
这是我选择中最好的答案。它允许安装多个软件包,但只安装那些尚未安装的软件包。
3赞 Pratik Patil 4/14/2015 #11

我已经实现了静默安装和加载所需 R 包的功能。希望可能会有所帮助。代码如下:

# Function to Install and Load R Packages
Install_And_Load <- function(Required_Packages)
{
    Remaining_Packages <- Required_Packages[!(Required_Packages %in% installed.packages()[,"Package"])];

    if(length(Remaining_Packages)) 
    {
        install.packages(Remaining_Packages);
    }
    for(package_name in Required_Packages)
    {
        library(package_name,character.only=TRUE,quietly=TRUE);
    }
}

# Specify the list of required packages to be installed and load    
Required_Packages=c("ggplot2", "Rcpp");

# Call the Function
Install_And_Load(Required_Packages);
5赞 Anish Sugathan 5/17/2015 #12

以下简单函数的工作方式类似于魅力:

  usePackage<-function(p){
      # load a package if installed, else load after installation.
      # Args:
      #   p: package name in quotes

      if (!is.element(p, installed.packages()[,1])){
        print(paste('Package:',p,'Not found, Installing Now...'))
        install.packages(p, dep = TRUE)}
      print(paste('Loading Package :',p))
      require(p, character.only = TRUE)  
    }

(不是我的,前段时间在网上找到的,从那时起一直在使用它。

1赞 Phantom Photon 6/13/2015 #13

这是我的代码:

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)
5赞 Samir 7/25/2015 #14

我使用以下功能来安装软件包,如果退出并出现找不到软件包错误。它将查询 CRAN 和 Bioconductor 存储库中缺少的包。require("<package>")

改编自约书亚·威利(Joshua Wiley)的原著,http://r.789695.n4.nabble.com/Install-package-automatically-if-not-there-td2267532.html

install.packages.auto <- function(x) { 
  x <- as.character(substitute(x)) 
  if(isTRUE(x %in% .packages(all.available=TRUE))) { 
    eval(parse(text = sprintf("require(\"%s\")", x)))
  } else { 
    #update.packages(ask= FALSE) #update installed packages.
    eval(parse(text = sprintf("install.packages(\"%s\", dependencies = TRUE)", x)))
  }
  if(isTRUE(x %in% .packages(all.available=TRUE))) { 
    eval(parse(text = sprintf("require(\"%s\")", x)))
  } else {
    source("http://bioconductor.org/biocLite.R")
    #biocLite(character(), ask=FALSE) #update installed packages.
    eval(parse(text = sprintf("biocLite(\"%s\")", x)))
    eval(parse(text = sprintf("require(\"%s\")", x)))
  }
}

例:

install.packages.auto(qvalue) # from bioconductor
install.packages.auto(rNMF) # from CRAN

PS:&将更新系统上所有已安装的软件包。这可能需要很长时间,并将其视为完整的 R 升级,可能并不总是得到保证!update.packages(ask = FALSE)biocLite(character(), ask=FALSE)

评论

0赞 Holger Brandl 5/12/2016
可以通过检查软件包是否真的可以在 cran 或 bc 上使用来改进它。此外,如果安装失败或包不存在,它应该在末尾使用库来抛出错误。请参阅我的改进版本,称为 raw.githubusercontent.com/holgerbrandl/datautils/master/R/...loadpack()
2赞 ruemorgue 11/7/2015 #15
 48 lapply_install_and_load <- function (package1, ...)
 49 {
 50     #
 51     # convert arguments to vector
 52     #
 53     packages <- c(package1, ...)
 54     #
 55     # check if loaded and installed
 56     #
 57     loaded        <- packages %in% (.packages())
 58     names(loaded) <- packages
 59     #
 60     installed        <- packages %in% rownames(installed.packages())
 61     names(installed) <- packages
 62     #
 63     # start loop to determine if each package is installed
 64     #
 65     load_it <- function (p, loaded, installed)
 66     {
 67         if (loaded[p])
 68         {
 69             print(paste(p, "loaded"))
 70         }
 71         else
 72         {
 73             print(paste(p, "not loaded"))
 74             if (installed[p])
 75             {
 76                 print(paste(p, "installed"))
 77                 do.call("library", list(p))
 78             }
 79             else
 80             {
 81                 print(paste(p, "not installed"))
 82                 install.packages(p)
 83                 do.call("library", list(p))
 84             }
 85         }
 86     }
 87     #
 88     lapply(packages, load_it, loaded, installed)
 89 }
3赞 jangorecki 11/26/2015 #16

很基本的一个。

pkgs = c("pacman","data.table")
if(length(new.pkgs <- setdiff(pkgs, rownames(installed.packages())))) install.packages(new.pkgs)
3赞 Ben 2/5/2016 #17

以为我会贡献我使用的那个:

testin <- function(package){if (!package %in% installed.packages())    
install.packages(package)}
testin("packagename")
7赞 Alex Essilfie 2/8/2016 #18

您可以简单地使用该函数来获取未安装的包,然后安装它们。在下面的示例中,我们在安装之前检查是否安装了 ggplot2Rcpp 包。setdiff

unavailable <- setdiff(c("ggplot2", "Rcpp"), rownames(installed.packages()))
install.packages(unavailable)

在一行中,上面可以写成:

install.packages(setdiff(c("ggplot2", "Rcpp"), rownames(installed.packages())))

评论

0赞 Scudelletti 5/23/2017
我使用相同的方法。我们也可以使用代替 .installed.packages()[,'Package']rownames(installed.packages())
1赞 s n 8/27/2016 #19
library <- function(x){
  x = toString(substitute(x))
if(!require(x,character.only=TRUE)){
  install.packages(x)
  base::library(x,character.only=TRUE)
}}

这适用于不带引号的软件包名称,并且相当优雅(参见 GeoObserver 的回答)

40赞 user6784955 9/2/2016 #20
if (!require('ggplot2')) install.packages('ggplot2'); library('ggplot2')

“ggplot2”是包。它会检查包是否已安装,如果未安装,则安装它。然后,无论它采用哪个分支,它都会加载包。

8赞 mtelesha 5/25/2017 #21

使用,使共享库完全相同,并且不会更改其他库的环境。packrat

在优雅和最佳实践方面,我认为你从根本上走错了路。该软件包是针对这些问题而设计的。它由 Hadley Wickham 的 RStudio 开发。他们不必安装依赖项并可能弄乱某人的环境系统,而是使用自己的目录并将程序的所有依赖项安装在那里,并且不触及某人的环境。packratpackrat

Packrat 是 R 的依赖管理系统。

R 包依赖项可能令人沮丧。你是否曾经不得不使用反复试验来弄清楚你需要安装哪些 R 包才能使别人的代码正常工作,然后永远全局安装这些包,因为现在你不确定是否需要它们?您是否曾经更新过一个包,以使其中一个项目中的代码正常工作,却发现更新的包使另一个项目中的代码停止工作?

我们构建了 packrat 来解决这些问题。使用 packrat 使 R 项目更多:

  • 独立:为一个项目安装新的或更新的包不会破坏其他项目,反之亦然。这是因为 packrat 为每个项目提供了自己的私有包库。
  • 便携:轻松将您的项目从一台计算机传输到另一台计算机,甚至跨不同平台。Packrat 可以轻松安装项目所依赖的软件包。
  • 可重现:Packrat 会记录您依赖的确切软件包版本,并确保这些确切的版本是无论您走到哪里都能安装的版本。

https://rstudio.github.io/packrat/

评论

1赞 StatsStudent 9/4/2023
我知道你在 2017 年发布了这个答案,在 出现之前,但如果其他人遇到这个答案,我想他们会从这个笔记中受益。在我看来,可以更好地处理所有这些的首选且更现代的软件包是 .我在此处添加了有关的详细信息,并提供了一些指向文档的链接,这些文档描述了为什么这是一个更好的软件包解决方案。事实上,在创建新的 R Studio 项目时,已替换为 R Studio 用户界面中的可重现环境解决方案。stackoverflow.com/a/77036762/4615298renvrenvrenvrenvpackrat
53赞 Matthew 6/21/2017 #22

上面的很多答案(以及这个问题的重复)都依赖于哪种形式不好。从文档中:installed.packages

当安装了数千个包时,这可能会很慢,因此不要使用它来确定是否安装了命名包(使用 system.file 或 find.package),也不要使用它来查找包是否可用(调用 require 并检查返回值),也不要查找少量包的详细信息(使用 packageDescription)。它需要读取每个已安装的软件包的多个文件,这在 Windows 和某些网络挂载的文件系统上会很慢。

因此,更好的方法是尝试使用 和 加载包,如果加载失败,则安装(如果未找到,将返回)。我更喜欢这种实现:requirerequireFALSE

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.packages

这是相同的功能,但有一个窗口对话框,询问用户是否要安装缺少的软件包

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)
        }
    }
}

评论

4赞 Bing 12/3/2018
这是一种非常优雅的方式,比公认的方式要好得多。我会把它收录在我的个人图书馆中。谢谢。
2赞 Pål Bjartan 4/27/2023
这是一个优雅的解决方案。但有一件事:是特定于平台的,并且仅限于 Windows。winDialog()
2赞 Shicheng Guo 6/22/2017 #23
source("https://bioconductor.org/biocLite.R")
if (!require("ggsci")) biocLite("ggsci")
1赞 teichert 12/21/2017 #24

就我而言,我想要一个可以从命令行运行的单行(实际上是通过 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")

除了以前的解决方案之外,这里没有其他内容:

  • 我把它保持在一行
  • 我对 repos 参数进行了硬编码(以避免任何弹出窗口询问要使用的镜像)
  • 我懒得定义要在其他地方使用的函数

还要注意重要的(如果没有它,require 将尝试加载包)。character.only=TRUEp

2赞 George Shimanovsky 8/28/2018 #25

使用 lapply family 和匿名函数方法,您可以:

  1. 尝试附加所有列出的包。
  2. 仅安装缺失(使用延迟评估)。||
  3. 尝试再次附加步骤 1 中缺少的、在步骤 2 中安装的那些。
  4. 打印每个包的最终加载状态 ( / )。TRUEFALSE

    req <- substitute(require(x, character.only = TRUE))
    lbs <- c("plyr", "psych", "tm")
    sapply(lbs, function(x) eval(req) || {install.packages(x); eval(req)})
    
    plyr psych    tm 
    TRUE  TRUE  TRUE 
    
7赞 Aurèle 3/5/2019 #26

RStudio 的当前版本 (>=1.2) 包括一项功能,用于检测缺少的包和调用,并提示用户安装它们:library()require()

检测缺少的 R 包

许多 R 脚本打开时都会调用和加载它们需要执行的包。如果打开引用尚未安装的包的 R 脚本,RStudio 现在将提供只需单击一下即可安装所有需要的包。无需再重复打字,直到错误消失!
https://blog.rstudio.com/2018/11/19/rstudio-1-2-preview-the-little-things/
library()require()install.packages()

这似乎特别很好地解决了 OP 最初的担忧:

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

0赞 KVemuri 10/12/2019 #27
  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)
}
1赞 lf_araujo 3/26/2020 #28

让我分享一点疯狂:

c("ggplot2","ggsci", "hrbrthemes", "gghighlight", "dplyr") %>%  # What will you need to load for this script?
  (function (x) ifelse(t =!(x %in% installed.packages()), 
    install.packages(x[t]),
    lapply(x, require))) 
36赞 MichaelChirico 7/9/2020 #29

TL;DR 可用于此目的。find.package()

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

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

  • require具有加载包命名空间的副作用,这可能并不总是可取的
  • installed.packages是点燃蜡烛的火箭筒 - 它将首先检查已安装的软件包的范围,然后我们检查我们的一个(或几个)软件包是否在这个库中“有货”。无需为了找到一根针而大海捞针。

这个答案的灵感也来自@ArtemKlevtsov本着类似的精神对这个问题的重复版本的伟大回答。他指出,如果没有安装软件包,可能会产生预期的返回效果,否则可能会产生预期的影响。system.file(package=x)''nchar > 1

如果我们看一下如何实现这一点,我们可以看到它使用了不同的函数,我们可以直接使用它:system.filebasefind.package

# 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.package.libPaths()pkgDESCRIPTIONfile.path(.libPaths(), pkg)file.exists(file.path(.libPaths(), pkg, 'DESCRIPTION')

评论

1赞 saQuist 10/7/2021
经过充分研究的答案!尽管如此,我对模棱两可的回报感到有些困惑:.在设计软件包安装链时,我应该只使用第一个布尔值吗?file.exists(file.path(.libPaths(), 'sf', 'DESCRIPTION')) [1] TRUE FALSE
1赞 MichaelChirico 10/7/2021
@saQuist是的,IINM 这就是 install.packages 的作用。实际上,它可能更像是一个 for 循环,循环 .libPaths() 并在成功后退出
0赞 user2363777 12/19/2023
当我将 find.package(my_package_name, quiet = TRUE) 包装到函数中时,nchar() 在这里抛出“参数长度为零”错误。
0赞 Raghvendra Yadav 11/14/2021 #30
pckg=c("shiny","ggplot2","dplyr","leaflet","lubridate","RColorBrewer","plotly","DT","shinythemes")

for(i in 1:length(pckg)) 
   {
      print(pckg[i])
      if (!is.element(pckg[i], installed.packages()[,1]))
      install.packages(pckg[i], dep = TRUE)
      require(pckg[i], character.only = TRUE)
}
1赞 eliot.mcintire 1/21/2022 #31

有一个新的包(我是共同开发人员),旨在成为可重现工作流的一部分,这意味着该函数在第一次运行时或后续运行时产生相同的输出,即无论起始状态如何,最终状态都是相同的。以下安装任何缺少的软件包(我包括严格解决原始问题......通常我将其保留为默认值,因为我通常希望将它们加载到搜索路径中)。Requirerequire = FALSE

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

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

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

5赞 hplieninger 3/25/2022 #32

今天,我偶然发现了 rlang 包提供的两个方便的功能,即 和 .is_installed()check_installed()

帮助页面(强调后加):

这些函数检查安装包时是否具有最小的副作用。如果已安装,则将加载包,但不会附加包。

is_installed()不与用户交互。它只是返回 OR,具体取决于是否安装了包。TRUEFALSE

交互式会话中,询问用户是否安装缺少的包。如果用户接受,则安装包 [...]。如果会话是非交互式的,或者用户选择不安装包,则当前评估将中止。check_installed()

interactive()
#> [1] FALSE
rlang::is_installed(c("dplyr"))
#> [1] TRUE
rlang::is_installed(c("foobarbaz"))
#> [1] FALSE
rlang::check_installed(c("dplyr"))
rlang::check_installed(c("foobarbaz"))
#> Error:
#> ! The package `foobarbaz` is required.

创建于 2022-03-25 由 reprex 软件包 (v2.0.1)

0赞 DomQ 9/24/2022 #33

站在@MichaelChirico的肩膀上:

stopifnot(3 == length(find.package(c('foo', 'bar', 'baz'))))
1赞 Johannes Titz 8/8/2023 #34

真的没有人使用吗?librarian

# install.packages("librarian") # install if you do not have it
librarian::shelf(Rcpp, tidyverse/ggplot2)

正如你所看到的,它甚至可以从github安装,没有引号,使其更加一致。此外,它还可以安装生物导体包。

2赞 StatsStudent 9/4/2023 #35

我意识到这是一个较老的问题,但最近几个月和几年来,R 中的许多技术都得到了极大的改进,以解决这个确切的问题。处理与可能安装在协作者计算机或目标计算机上的包依赖项共享代码的普遍接受的现代方法是使用 renv 包(“” 是“可重复环境”的缩写),该包于 2019 年 10 月下旬首次作为 0.8.0 提供。版本于 2023 年 7 月 7 日正式发布,截至本文发布时,当前的 CRAN 版本是 版本 ,于上个月于 2023 年 8 月 15 日发布renvrenv1.0.01.0.2

此包极大地帮助 R 协作者共享代码、包(其确切版本及其依赖项和版本),甚至跟踪用于在 R 项目中生成和执行代码的 R 的确切版本。

要使用它,通常初始程序员在 R Studio/Posit 中创建一个 R 项目,然后使用命令在项目中初始化。执行此操作时,R 将执行以下操作:renvrenv::init()

  1. 在项目中创建特定于项目的包库,而不是使用常规/全局库或库(例如,)。作为此步骤的一部分,还会创建一个目录,其中包含一些大多数用户通常不会打扰的设置和文件,因为会为您处理这个问题。.libPaths()renvrenvrenv
  2. 创建一个 .文件,这是特定于项目的 R 项目配置文件,用于将 R 配置为在打开项目时使用在步骤 1 中创建的项目特定库。Rprofile
  3. 创建一个在项目主目录中调用的锁定文件,该文件记录有关项目使用的所有包和版本的详细信息 -- 这就是使用与包和包/版本依赖项共享代码的最有吸引力的选项的原因。renv.lockrenv

使用命令初始化项目环境后,初始程序员将按照典型方式开发和编写代码,根据需要以通常的方式(例如,通过简单地进入控制台)安装软件包。但是,这些包存储在项目库中,而不是任何全局库中。当初始程序员认为代码处于令人满意的状态以共享整个项目时,他只需发出命令,该命令只需更新在上面的步骤 3 中创建的锁定文件,其中包含项目中使用的所有包的名称、版本号等。init()install.packages("PackageName")renv::snapshot()

此时,初始程序员可以与其他协作者共享项目(理想情况下,这是通过 GitHubBitbucketAzure DevOps 等完成的)。当任何新的协作者打开 R 项目时,他们只需在控制台中输入命令即可。这将安装项目中使用的每个包的完全相同的版本(并且它将还原到项目库中,而不是用户的全局包中)。renv::restore()

这是一个很好的工作流程,因为它将确保所有用户都使用与初始开发人员使用的相同版本的包。如果没有 ,协作者可能会在其全局库中安装了完全不同版本的 R 包,并且它的功能可能与初始开发人员的包不同。这可能会导致代码中断,或者更糟的是,运行,但会导致不同的输出,最终用户可能不知道。renv

正如 renv 简介中完美描述的那样,它通过确保包隔离、跨用户和环境的可重复性以及可移植性使用户受益。 还享有其他一些好处,例如缓存 R 包,以便在跨项目使用时不必多次下载它们。它还适用于 Python 和 Python 包。如果还希望确保环境的每个细节(包括操作系统和其他外部(对 R/R Studio)依赖项)都已到位,也可以通过与 Docker 映像结合使用来完全容器化解决方案,从而轻松实现此目的!renvrenv()renv

最后一点:如果看起来与 相似,那是因为它在某种程度上是。事实上,最初尝试使用构建可复制的环境包,但在与它的局限性作斗争后放弃了并“推出了自己的环境包”。但我认为,它也要好得多。好消息是,如果您已经在使用并想升级到这个现代工具,您可以使用命令轻松完成!renvpackratrevpackratpackratrenv::migrate()

祝你好运,合作愉快!