优雅的方法来检查丢失的包并安装它们?

Mai*_*ura 307 packages r r-faq

这些天我似乎与共同作者分享了很多代码.他们中的许多人都是初级/中级R用户,并没有意识到他们必须安装他们尚未拥有的软件包.

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

Sha*_*ane 269

是.如果您有包列表,请将其与输出进行比较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)
Run Code Online (Sandbox Code Playgroud)

除此以外:

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

  • 我认为正确的语法是:`if(length(new.packages)> 0){install.packages(new.packages)}` (9认同)
  • instal.packages的文档声明:"当安装了数千个软件包时,这可能会很慢,所以不要使用它来查明是否安装了命名软件包(使用system.file或find.package)..." (7认同)
  • @psql,Shine是对的,因为"> 0"在if条件中是"隐含的".运行它来验证它:`new.packages < - c(1,2)``length(new.packages)``if(length(new.packages)){print("hello!")} else {print ("哦不!")}` (4认同)
  • 同意Thomas,使用`require`而不是检查`installed.packages`会有更好的表现 (2认同)

Tyl*_*ker 203

Dason K.和我有pacman包可以做得很好.p_load包中的功能可以做到这一点.第一行是为了确保安装pacman.

if (!require("pacman")) install.packages("pacman")
pacman::p_load(package1, package2, package_n)
Run Code Online (Sandbox Code Playgroud)

  • 现在安装并且运行得非常好; 应该是基地的一部分! (6认同)
  • @MERose**pacman**现在在CRAN上http://cran.r-project.org/web/packages/pacman/index.html (4认同)
  • @NealBarsch如果你的意思是`if(!require("pacman"))install.packages("pacman")`pacman中有一个名为`p_boot()的函数,它会自动为你生成这一行并将它复制到剪贴板. (4认同)
  • 这样做的唯一方法是检查`/`,如果找到,则自动从github安装/加载. (3认同)

Liv*_*ius 63

你可以使用以下的返回值require:

if(!require(somepackage)){
    install.packages("somepackage")
    library(somepackage)
}
Run Code Online (Sandbox Code Playgroud)

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

dynamic_require <- function(package){
  if(eval(parse(text=paste("require(",package,")")))) return True

  install.packages(package)
  return eval(parse(text=paste("require(",package,")")))
}
Run Code Online (Sandbox Code Playgroud)

这种方法的缺点是你必须在引号中传递包名,而不是真实的require.

  • 你可以通过在`require`中使用`character.only = TRUE'来简化你的生活,但是我想没有什么可以区分你的答案. (4认同)
  • 谢谢@Livius。真的很喜欢eval的把戏。 (2认同)

Sim*_*lon 18

此解决方案将采用包名称的字符向量并尝试加载它们,或者在加载失败时安装它们.它依赖于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" ) )
Run Code Online (Sandbox Code Playgroud)


Mic*_*ico 18

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

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

  • require 具有加载包命名空间的副作用,这可能并不总是可取的
  • installed.packages是火箭筒光蜡烛-它会检查宇宙第一安装的软件包,然后我们检查,如果我们的一个(或几个)包(S)是“股票”在这个库。无需为了找到一根针而建造大海捞针。

这个答案也受到@ArtemKlevtsov在这个问题的重复版本上以类似的精神做出的伟大回答的启发。他指出,如果未安装软件包,system.file(package=x)可能会产生所需的返回效果'',以及nchar > 1否则会产生一些影响。

如果我们深入了解如何system.file实现这一点,我们会发现它使用了一个不同的base函数,find.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)
Run Code Online (Sandbox Code Playgroud)

我们也可以深入find.package了解它是如何工作的,但这主要是一个有指导意义的练习——我看到的缩小函数的唯一方法是跳过一些健壮性检查。但基本思想是:查看.libPaths()- 任何已安装的包pkg都会有一个位于 的DESCRIPTION文件file.path(.libPaths(), pkg),因此快速检查是file.exists(file.path(.libPaths(), pkg, 'DESCRIPTION').


小智 16

if (!require('ggplot2')) install.packages('ggplot2'); library('ggplot2')
Run Code Online (Sandbox Code Playgroud)

"ggplot2"是包.它会检查软件包是否已安装,如果不安装软件包.然后它加载包,无论它采用哪个分支.


Mat*_*hew 16

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

当安装了数千个软件包时,这可能会很慢,所以不要使用它来查明是否安装了命名软件包(使用system.file或find.package),也不知道软件包是否可用(调用require并检查返回值)也没有找到少量包的细节(使用packageDescription).它需要为每个已安装的软件包读取多个文件,这在Windows和某些网络安装的文件系统上会很慢.

因此,更好的方法是尝试使用require和加载包,并在加载失败时安装(如果找不到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)
    }
}
Run Code Online (Sandbox Code Playgroud)

可以像这样使用:

using("RCurl","ggplot2","jsonlite","magrittr")
Run Code Online (Sandbox Code Playgroud)

这样它就可以加载所有的包,然后返回并安装所有丢失的包(如果你愿意的话,这是一个方便的地方,可以插入提示询问用户是否要安装包).它不是install.packages为每个包单独调用,而是仅传递一次卸载包的整个向量.

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

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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一种非常优雅的方式,比公认的方式要好得多。我会将其添加到我的个人图书馆中。谢谢。 (4认同)
  • 这是一个优雅的解决方案。但有一件事:“winDialog()”是特定于平台的,并且仅限于 Windows。 (2认同)

Jua*_*ano 15

虽然巴蒂尔的答案是真的好,我的项目之一,我需要去掉输出中的消息,警告并安装软件包自动的.我终于设法得到这个脚本:

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)
}
Run Code Online (Sandbox Code Playgroud)

使用:

libraries <- c("ReadImages", "ggplot2")
for(library in libraries) 
{ 
    if(!UsePackage(library))
    {
        stop("Error!", library)
    }
}
Run Code Online (Sandbox Code Playgroud)


Bri*_*ing 8

# 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)
Run Code Online (Sandbox Code Playgroud)

  • 这是我的选择中最好的答案。它允许安装多个软件包,但只安装那些尚未安装的软件包。 (2认同)

mte*_*sha 8

使用packrat以便共享库完全相同并且不改变其他环境。

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

Packrat 是 R 的依赖管理系统。

R 包依赖性可能令人沮丧。您是否曾经不得不使用试错法来确定需要安装哪些 R 包才能使其他人的代码正常工作——然后将这些包永久安装在全局范围内,因为现在您不确定是否需要它们? 您是否曾经更新过一个包以使您的一个项目中的代码工作,却发现更新的包使另一个项目中的代码停止工作?

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

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

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


Ale*_*fie 7

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

unavailable <- setdiff(c("ggplot2", "Rcpp"), rownames(installed.packages()))
install.packages(unavailable)
Run Code Online (Sandbox Code Playgroud)

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

install.packages(setdiff(c("ggplot2", "Rcpp"), rownames(installed.packages())))
Run Code Online (Sandbox Code Playgroud)


Eri*_*lts 6

这是rbundler软件包的目的:提供一种控制为特定项目安装的软件包的方法.现在,该软件包与devtools功能一起使用,可以将软件包安装到项目的目录中.该功能类似于Ruby的捆绑器.

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

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

现在这些包将安装在.Rbundle目录中.

如果您的项目不是软件包,那么您可以通过DESCRIPTION在项目的根目录中创建一个文件来伪装它,其中Depends字段列出了您要安装的软件包(带有可选的版本信息):

Depends: ggplot2 (>= 0.9.2), arm, glmnet
Run Code Online (Sandbox Code Playgroud)

如果您有兴趣贡献,那么这是该项目的github回购:rbundler.


Dir*_*tel 5

当然.

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

所以做点什么

AP <- available.packages(contrib.url(repos[i,"url"]))   # available t repos[i]
Run Code Online (Sandbox Code Playgroud)

获取所有已知的包,对当前安装的包进行类似调用,并将其与给定的一组目标包进行比较.


小智 5

下面的简单函数就像一个魅力:

  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)  
    }
Run Code Online (Sandbox Code Playgroud)

(不是我的,前段时间在网上找到了这个,从那时起就一直在使用它。不确定原始来源)


Sam*_*mir 5

如果require("<package>")退出时出现包未找到错误,我使用以下函数来安装包。它将查询 - CRAN 和 Bioconductor 存储库以查找丢失的包。

改编自 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)))
  }
}
Run Code Online (Sandbox Code Playgroud)

例子:

install.packages.auto(qvalue) # from bioconductor
install.packages.auto(rNMF) # from CRAN
Run Code Online (Sandbox Code Playgroud)

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


Aur*_*èle 5

即将推出的 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 的新手/中级用户,并没有意识到他们必须安装他们还没有的软件包。


hpl*_*ger 5

今天,我偶然发现了 rlang 包提供的两个方便的函数,即is_installed()check_installed()

帮助页面(添加了重点):

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

is_installed()不与用户交互。它只是返回TRUEorFALSE取决于是否安装了软件包。

交互式会话中,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.
Run Code Online (Sandbox Code Playgroud)

由reprex 包(v2.0.1)于 2022 年 3 月 25 日创建