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

问题描述 投票:283回答:26

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

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

r packages r-faq
26个回答
252
投票

是。如果您有包列表,请将其与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)

除此以外:

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


5
投票

当然。

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

所以做点什么

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

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


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升级,可能无法保证!


4
投票

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

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

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

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

4
投票

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

在优雅和最佳实践方面,我认为你从根本上讲是错误的。包packrat是为这些问题而设计的。它由Htley Wickham的RStudio开发。而不是他们必须安装依赖项并可能搞砸某人环境系统packrat使用自己的目录并在其中安装程序的所有依赖项,并且不会触及某人的环境。

Packrat是R的依赖管理系统。

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

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

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

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


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

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


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
投票

使用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

193
投票

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

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

2
投票

即将推出的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用户,并没有意识到他们必须安装他们尚未拥有的软件包。


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
投票
source("https://bioconductor.org/biocLite.R")
if (!require("ggsci")) biocLite("ggsci")

0
投票

在我的情况下,我想要一个可以从命令行运行的单行程序(实际上通过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)。


57
投票

你可以使用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


17
投票

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

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

15
投票
if (!require('ggplot2')) install.packages('ggplot2'); library('ggplot2')

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


13
投票

上面的许多答案(以及这个问题的重复)都依赖于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)
        }
    }
}

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)

6
投票

这是rbundler package的目的:提供一种控制为特定项目安装的包的方法。现在,该软件包与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

© www.soinside.com 2019 - 2024. All rights reserved.