代码之家  ›  专栏  ›  技术社区  ›  Maiasaura

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

  •  280
  • Maiasaura  · 技术社区  · 15 年前

    最近我似乎和合著者分享了很多代码。他们中的许多人都是新手/中级R用户,并没有意识到他们必须安装他们还没有的软件包。

    有优雅的方式打电话吗 installed.packages() ,是否将其与我正在加载和安装的文件(如果丢失)进行比较?

    26 回复  |  直到 7 年前
        1
  •  241
  •   Shane    15 年前

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

    否则:

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

        2
  •  185
  •   Tyler Rinker DaniM    11 年前

    达森K.和我有 帕克曼 可以很好地完成这一任务的包。函数 p_load 在包中执行此操作。第一行只是为了确保安装了Pacman。

    if (!require("pacman")) install.packages("pacman")
    pacman::p_load(package1, package2, package_n)
    
        3
  •  55
  •   Axeman    9 年前

    您只需使用 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,")")))
    }
    

    这种方法的缺点是,您必须用引号传递包名,而不是用真正的 要求 .

        4
  •  17
  •   Simon O'Hanlon    12 年前

    此解决方案将获取包名称的字符向量并尝试加载它们,或者在加载失败时安装它们。它依赖于 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" ) )
    
        5
  •  15
  •   Juan Antonio Cano    14 年前

    虽然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)
        }
    }
    
        6
  •  13
  •   mpalanco    9 年前
    if (!require('ggplot2')) install.packages('ggplot2'); library('ggplot2')
    

    “ggplot2”是包装。它检查包是否已安装,如果未安装,则安装包。然后,它将加载包,而不管它使用哪个分支。

        7
  •  11
  •   Matthew    9 年前

    上面的许多答案(以及这个问题的副本)都依赖于 installed.packages 这是不好的形式。从文档中:

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

    因此,更好的方法是尝试使用 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
  •  8
  •   Brian Spiering    12 年前
    # 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)
    
        9
  •  6
  •   Erik Shilts    13 年前

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

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

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

    现在,包将安装在.rbundle目录中。

    如果你的项目不是一个包,那么你可以通过创建一个 描述 项目根目录中的文件,其“依赖”字段列出了要安装的包(包含可选版本信息):

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

    以下是项目的Github回购协议,如果您有兴趣参与: rbundler .

        10
  •  5
  •   Dirk is no longer here    15 年前

    当然。

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

    所以做一些类似的事情

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

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

        11
  •  4
  •   Anish Sugathan    11 年前

    以下简单的函数工作起来很有魅力:

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

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

        12
  •  4
  •   Samir    11 年前

    如果 require("<package>") 存在“找不到包”错误的退出。它将查询-cran和bioconductor存储库中的丢失包。

    改编自乔舒亚·威利的原作, 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升级,可能不是所有的时间都保证!

        13
  •  4
  •   Alex Essilfie    10 年前

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

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

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

    install.packages(setdiff(c("ggplot2", "Rcpp"), rownames(installed.packages())))
    
        14
  •  3
  •   Pratik Patil    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);
    
        15
  •  3
  •   mtelesha    8 年前

    使用 packrat 这样共享库就完全相同,不会改变其他库的环境。

    在优雅和最佳实践方面,我认为你根本上是错误的。包裹 包装鼠 是为这些问题而设计的。它是由哈雷·威克姆的RSTUDIO开发的。而不是他们必须安装依赖项,并可能破坏某人的环境系统 包装鼠 使用它自己的目录,并将程序的所有依赖项安装到它们的目录中,而不影响其他人的环境。

    Packrat是一个R的依赖性管理系统。

    R包依赖性可能令人沮丧。您是否曾经使用试用版和错误版来确定您需要安装哪些R软件包才能使其他人的代码工作,然后永远留在全球安装的软件包中,因为现在您不确定是否需要这些软件包?您是否曾经更新过一个包以使您的某个项目中的代码能够工作,结果发现更新后的包会使另一个项目中的代码停止工作?

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

    • 孤立:为一个项目安装新的或更新的包不会破坏您的其他项目,反之亦然。因为Packrat为每个项目提供了自己的私有包库。
    • 便携式:轻松地将项目从一台计算机传输到另一台计算机,甚至跨不同的平台。packrat使安装项目所依赖的包变得容易。
    • 可复制:packrat会记录您所依赖的确切的软件包版本,并确保这些确切的版本是在任何地方安装的版本。

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

        16
  •  2
  •   Michael Petrotta user3140870    12 年前

    关于您的主要目标“安装他们还没有的库”。不管使用“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”)

        17
  •  2
  •   jangorecki    10 年前

    相当基础。

    pkgs = c("pacman","data.table")
    if(length(new.pkgs <- setdiff(pkgs, rownames(installed.packages())))) install.packages(new.pkgs)
    
        18
  •  2
  •   Ben    10 年前

    我想我会贡献我所用的:

    testin <- function(package){if (!package %in% installed.packages())    
    install.packages(package)}
    testin("packagename")
    
        19
  •  2
  •   George Shimanovsky    7 年前

    使用laply家族和匿名函数方法,您可以:

    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 
      
        20
  •  1
  •   metasequoia    13 年前

    我使用以下方法检查包是否已安装,如果依赖项已更新,则加载包。

    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, ])
    }
    
        21
  •  1
  •   Edward Tyler    11 年前

    这是我的代码:

    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)
    
        22
  •  1
  •   ruemorgue    10 年前
     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 }
    
        23
  •  1
  •   s n    9 年前
    library <- function(x){
      x = toString(substitute(x))
    if(!require(x,character.only=TRUE)){
      install.packages(x)
      base::library(x,character.only=TRUE)
    }}
    

    这与未加引号的包名一起工作,并且相当优雅(参见geobserver的答案)

        24
  •  1
  •   Shicheng Guo    9 年前
    source("https://bioconductor.org/biocLite.R")
    if (!require("ggsci")) biocLite("ggsci")
    
        25
  •  1
  •   Aurèle    7 年前

    即将推出的rstudio(1.2)版本已经作为预览版提供,将包含一项功能,用于检测 library() require() 调用并提示用户安装它们:

    检测缺少的R包

    许多r脚本通过调用打开 图书馆() 要求() 加载执行所需的包。如果您打开一个r脚本,引用您尚未安装的软件包,那么rstudio现在将提供一次单击即可安装所有需要的软件包。不再打字 install.packages() 不断重复直到错误消失!
    https://blog.rstudio.com/2018/11/19/rstudio-1-2-preview-the-little-things/

    这似乎很好地解决了OP最初的问题:

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

        26
  •  0
  •   teichert    8 年前

    在我的例子中,我需要一个可以从命令行(实际上是通过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 )

    推荐文章