412

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

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

4

31 回答 31

369

是的。如果您有软件包列表,请将其与输出进行比较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)

除此以外:

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

于 2010-11-03T18:13:09.153 回答
279

Dason K. 和我有pacman包可以很好地做到这一点。包中的函数p_load就是这样做的。第一行只是为了确保安装了 pacman。

if (!require("pacman")) install.packages("pacman")
pacman::p_load(package1, package2, package_n)
于 2013-11-09T07:55:32.353 回答
80

您可以只使用的返回值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.

于 2013-11-09T01:00:06.247 回答
36

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

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

因此,更好的方法是尝试使用requireand 加载包,如果加载失败则安装(如果找不到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)
    }
}

可以这样使用:

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)
        }
    }
}
于 2017-06-20T18:37:08.063 回答
35
if (!require('ggplot2')) install.packages('ggplot2'); library('ggplot2')

“ggplot2”是包。它检查是否安装了软件包,如果没有安装它。然后无论它采用哪个分支,它都会加载包。

于 2016-09-01T20:02:56.113 回答
24

此解决方案将采用包名称的字符向量并尝试加载它们,或者如果加载失败则安装它们。它依赖于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" ) )
于 2013-11-08T23:20:13.147 回答
22

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

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

  • require具有加载包的命名空间的副作用,这可能并不总是可取的
  • installed.packages是一个点燃蜡烛的火箭筒——它会首先检查已安装包的宇宙,然后我们检查我们的一个(或几个)包是否在这个库中“有货”。没有必要为了找一根针而建立一个干草堆。

这个答案也受到@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)

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

于 2020-07-09T07:01:29.730 回答
16

虽然 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)
    }
}
于 2012-01-14T16:14:01.447 回答
11
# 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)
于 2014-02-16T01:05:12.073 回答
8

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

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

Packrat 是 R 的依赖管理系统。

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

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

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

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

于 2017-05-25T14:41:40.380 回答
7

这是rbundler 包的目的:提供一种方法来控制为特定项目安装的包。现在,该包使用 devtools 功能将包安装到您的项目目录。该功能类似于 Ruby 的bundler

如果您的项目是一个包(推荐),那么您所要做的就是加载 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

于 2012-12-02T20:55:07.093 回答
7

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

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

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

install.packages(setdiff(c("ggplot2", "Rcpp"), rownames(installed.packages())))
于 2016-02-08T08:05:58.943 回答
6

当然。

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

所以做类似的事情

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

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

于 2010-11-03T18:14:59.240 回答
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)  
    }

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

于 2015-05-17T15:34:51.583 回答
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)))
  }
}

例子:

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

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

于 2015-07-24T22:05:20.903 回答
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 用户,并且没有意识到他们必须安装他们还没有的软件包。

于 2019-03-05T10:13:54.690 回答
3

我已经实现了静默安装和加载所需 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);
于 2015-04-14T08:19:52.563 回答
3

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

testin <- function(package){if (!package %in% installed.packages())    
install.packages(package)}
testin("packagename")
于 2016-02-04T18:46:10.943 回答
2

关于您的主要目标“安装他们还没有的库。”并且无论使用“ 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 的老式方式加载和安装包。 require ("ggplot2") require ("Rcpp")

于 2013-11-11T18:32:04.783 回答
2
 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 }
于 2015-11-07T13:36:29.253 回答
2

很基础的一个。

pkgs = c("pacman","data.table")
if(length(new.pkgs <- setdiff(pkgs, rownames(installed.packages())))) install.packages(new.pkgs)
于 2015-11-26T01:47:54.277 回答
2
source("https://bioconductor.org/biocLite.R")
if (!require("ggsci")) biocLite("ggsci")
于 2017-06-22T02:27:46.693 回答
2

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

  1. 尝试附加所有列出的包。
  2. 仅安装缺失(使用||惰性评估)。
  3. 尝试再次附加在步骤 1 中丢失并在步骤 2 中安装的那些。
  4. 打印每个包裹的最终装载状态 ( TRUE/ FALSE)。

    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 
    
于 2018-08-28T12:04:44.517 回答
1

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

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, ])
}
于 2012-12-02T15:24:20.743 回答
1

这是我的代码:

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)
于 2015-06-12T16:22:47.573 回答
1
library <- function(x){
  x = toString(substitute(x))
if(!require(x,character.only=TRUE)){
  install.packages(x)
  base::library(x,character.only=TRUE)
}}

这适用于未引用的包名称并且相当优雅(参见 GeoObserver 的答案)

于 2016-08-26T17:47:53.753 回答
1

就我而言,我想要一个可以从命令行运行(实际上是通过 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(以避免任何弹出窗口询问要使用的镜像)
  • 我懒得定义要在别处使用的函数

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

于 2017-12-20T19:54:21.137 回答
1

让我分享一点疯狂:

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))) 
于 2020-03-25T23:21:01.983 回答
1

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

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

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

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

于 2022-01-20T23:27:13.520 回答
0
  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)
}
于 2019-10-11T20:55:41.740 回答
0
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)
}
于 2021-11-14T06:30:25.280 回答