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


336

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

有没有一种优雅的调用方式,installed.packages()如果缺少的话,可以与我正在加载和安装的方式进行比较吗?


1
@krlmlr接受的答案过时了,需要修改吗?在下,它对我有用(一些快速测试)R version 3.0.2 (2013-09-25) x86_64-w64-mingw32/x64 (64-bit)
Brian Diggs

1
@BrianDiggs:至少出现了三个解决此问题的软件包,下面仅引用其中一个。还有更多-这就是问题。
krlmlr

2
@krlmlr关于使用软件包来确保(其他)拥有必要的软件包,似乎有点讽刺意味。但肯定值得让一个了解他们的人写下答案。
Brian Diggs 2013年

2
@BrianDiggs:引导此安装检查程序包是必要的麻烦,但很小。当然,除非该功能进入了base... ;-)
krlmlr

Answers:


304

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

除此以外:

如果将代码放在软件包中并使其具有依赖性,则在安装软件包时将自动安装它们。


11
我认为正确的语法是: if(length(new.packages)>0) {install.packages(new.packages)}

5
@psql,Shine是正确的,因为if条件中的“> 0”是“隐式”的。运行此文件进行验证:new.packages <- c(1,2) length(new.packages) if(length(new.packages)){print("hello!")}else{print("oh no!")}
Andrea Cirillo

7
install.packages的文档指出:“当安装成千上万个软件包时,这可能会很慢,因此请不要使用它来确定是否已安装命名软件包(使用system.file或find.package)...”
Thomas Materna'5

2
同意托马斯(Thomas)的观点,require而不是进行检查,这将是更好的表现installed.packages
Matthew

1
packrat为此。它是可复制的包装管理系统。这种方式将以错误的方式进行处理,并且会干扰其他人的环境并且是不可复制的。Packrat拥有自己的共享库文件夹和环境。rstudio.github.io/packrat
mtelesha

231

Dason K.和我有pacman软件包,可以很好地做到这一点。p_load包中的函数可以执行此操作。第一行只是为了确保已安装pacman。

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

1
包裹的状态如何?我看不到C-RAN。
MERose


6
现在已经安装并且运行良好;应该是基地的一部分!
AndyF

3
更好的唯一方法是检查/并自动从github安装/加载(如果找到)。
空袭

4
@NealBarsch(如果您是说if (!require("pacman")) install.packages("pacman")pacman中有一个函数),该函数p_boot()自动为您添加该行并将其复制到剪贴板。
泰勒·林克

72

您可以只使用返回值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,")")))
}

这种方法的缺点是必须用引号将包名传递,而对real则不需要require


4
使用character.only = TRUEin 可以大大简化您的生活require,但是我想没有什么可以与您的答案区分开。
Simon O'Hanlon 2013年

看起来不错,但似乎不起作用,至少对我而言。当我尝试此功能的强大版本时,由于R由于某种原因不知道如何处理“返回True”和“返回评估”,因此我收到两条错误消息。所以我真的很喜欢这样一个函数,如果我的库中有它,则加载一个包,然后安装(然后加载)该包。理想情况下,然后将其用作加载程序包的默认设置。至少这样做似乎很有意义,并且可以节省一些时间。
Fabian Habersack

23
if (!require('ggplot2')) install.packages('ggplot2'); library('ggplot2')

“ ggplot2”是软件包。它检查是否已安装该软件包,如果未安装,则将其安装。然后,无论装入哪个分支,都将装入程序包。


21

此解决方案将采用包名称的字符向量并尝试加载它们,或者在加载失败时安装它们。它依赖于的返回行为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" ) )

你不想打电话吗 require安装后,再次?
krlmlr

@krlmlr不,因为要对if语句进行求值,必须先求值require,如果有的话,副作用是正在加载程序包!
西蒙·奥汉隆

1
SimonO101:我认为krlmlr在调用之后的if语句中表示install.packages,因为这实际上不会加载该程序包。但是(对@krlmlr)我怀疑其意图是该代码片段只会被调用一次。您不会在每次需要软件包时都写这个。相反,您可以提前运行一次,然后require根据需要照常调用。
Aaron

@Aaron啊,是的,我明白你的意思了,是的,你的解释是正确的。我将对其稍作修改,以更明确地说明安装后的加载。
西蒙·奥汉隆

1
如果第二require个调用仍是更好的选择,library以至于由于某种原因仍无法附加该程序包,则发出很大的响声会更好吗?
卡布杜拉

18

上面的许多答案(以及该问题的重复项)都取决于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)
    }
}

可以这样使用:

using("RCurl","ggplot2","jsonlite","magrittr")

这样,它将加载所有软件包,然后返回并安装所有缺少的软件包(如果需要,可以在该位置方便地插入提示询问用户是否要安装软件包)。而不是打电话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)
        }
    }
}

这是一种非常优雅的方法,比公认的方法好得多。我会将其包含在我的个人图书馆中。谢谢。
必应

15

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

9
# 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)

6

这是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


5

当然。

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

所以做类似的事情

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

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


5

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

在优雅和最佳实践方面,我认为您从根本上来说是错误的做法。该软件包packrat是为解决这些问题而设计的。它由Hadley Wickham的RStudio开发。他们不必安装依赖关系并可能弄乱某个人的环境系统,而packrat使用它们自己的目录并在其中安装程序的所有依赖关系,而不会碰到某个人的环境。

Packrat是R的依赖项管理系统。

R软件包的依赖关系可能令人沮丧。您是否曾经使用过反复试验来确定需要安装哪些R软件包才能使其他人的代码正常工作,然后再将这些软件包永久地全局安装,因为现在您不确定是否需要它们?您是否曾经更新过一个程序包以使一个项目中的代码能够正常工作,却发现更新后的程序包使另一个项目中的代码停止工作了?

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

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

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


4

以下简单功能就像一个超级按钮一样工作:

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

(不是我的,很早以前就在网上找到了这个,并且从那以后一直在使用它。不确定原始来源)


4

如果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升级,可能并不总是保证!


可以通过检查软件包是否确实适用于cran或bc来进行改进。此外,如果安装失败或不存在软件包,则应在最后使用库抛出错误。请参阅我loadpack()raw.githubusercontent.com/holgerbrandl/datautils/master/R/
Holger Brandl,

4

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

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

在一行中,以上内容可以写成:

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

我使用相同的方法。我们也可以使用installed.packages()[,'Package']代替rownames(installed.packages())
Scudelletti

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

3

即将发布的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新手/中级用户,他们没有意识到他们必须安装尚未拥有的软件包。


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


如果您不喜欢自己的答案,请不要破坏它-只需删除它即可。
Michael Petrotta

好吧,我尝试过,但是我做不到。我认为我的FF的NoScript扩展正在禁用它,或者我无权删除自己的答案。大声笑但是,我认为Livius非常接近我的答案,认为没有掩饰。谢谢迈克尔·彼得罗塔(Michael Petrotta)。通知。
GeoObserver

您应该delete在这些评论上方看到一个链接。如果不是这样,但仍然要删除,请使用flag链接,选择“其他”,并向主持人解释您希望删除答案。
Michael Petrotta

2

很基本的。

pkgs = c("pacman","data.table")
if(length(new.pkgs <- setdiff(pkgs, rownames(installed.packages())))) install.packages(new.pkgs)

2

以为我会用我所用的:

testin <- function(package){if (!package %in% installed.packages())    
install.packages(package)}
testin("packagename")

2
source("https://bioconductor.org/biocLite.R")
if (!require("ggsci")) biocLite("ggsci")

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 

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

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)

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

1
library <- function(x){
  x = toString(substitute(x))
if(!require(x,character.only=TRUE)){
  install.packages(x)
  base::library(x,character.only=TRUE)
}}

这适用于未加引号的包名称,并且相当优雅(请参阅GeoObserver的答案)


1

就我而言,我想要一个可以从命令行运行的衬板(实际上是通过Makefile运行)。如果尚未安装“ VGAM”和“羽毛”,请参见以下示例:

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


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

0

让我分享一下疯狂:

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))) 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.