Home Articles

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

Asked
Viewed 773 times
256

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

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

26 Answers

  • 229
    # 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)
    
  • 170

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

    除此以外:

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

  • 51

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

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

    Dason K.和我有 pacman 包可以做得很好 . 包中的函数 p_load 执行此操作 . 第一行是为了确保安装pacman .

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

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

    当安装了数千个软件包时,这可能会很慢,所以不要使用它来查明是否安装了命名软件包(使用system.file或find.package),也不知道软件包是否可用(调用require和check返回值)也没有找到少量包的细节(使用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)
            }
        }
    }
    
  • 12

    我已经实现了静默安装和加载所需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);
    
  • 10

    相当基本的一个 .

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

    这是rbundler package的目的:提供一种控制为特定项目安装的包的方法 . 现在,该软件包使用devtools功能将软件包安装到您的项目's directory. The functionality is similar to Ruby' s bundler .

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

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

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

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

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

    这里's the github repo for the project if you'对贡献感兴趣:rbundler .

  • 6

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

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

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

  • 4

    虽然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)
        }
    }
    
  • 4

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

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

    • 尝试附加所有列出的包 .

    • 仅安装缺失(使用 || 延迟评估) .

    • 尝试再次附加步骤1中缺少的那些并在步骤2中安装 .

    • 打印每个包的最终加载状态( 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
    
  • 3

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

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

    这与未加引用的包名称一起使用并且非常优雅(参见GeoObserver的答案)

  • 2

    当然 .

    您需要将'installed packages'与'desired packages'进行比较 . 这与我对CRANberries的处理非常接近,因为我需要将'stored known packages'与'currently known packages'进行比较以确定新的和/或更新的包 .

    所以做点什么

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

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

  • 2

    以下简单的功能就像一个魅力:

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

    (不是我的,一段时间后在网上发现这个并且从那时起一直在使用它 . 不确定原始来源)

  • 2

    这是我的代码:

    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)
    
  • 2

    试试这个:

    if (!require(MyDesiredLibrary)) {
       install.packages("MyDesiredLibrary")
    }
    
  • 1

    您只需使用 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 .

  • 1

    您只需使用 setdiff 函数即可获取未安装的软件包,然后再安装它们 . 在下面的示例中,我们检查是否安装了 ggplot2Rcpp 软件包,然后再进行安装 .

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

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

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

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

    testin <- function(package){if (!package %in% installed.packages())    
    install.packages(package)}
    testin("packagename")
    
  • 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
    source("https://bioconductor.org/biocLite.R")
    if (!require("ggsci")) biocLite("ggsci")
    
  • 0

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

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

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

    Packrat是R的依赖管理系统.R包依赖可能令人沮丧 . 您是否曾经不得不使用反复试验来确定需要安装哪些R软件包才能使其他人的代码正常工作 - 然后将这些软件包永久保留在全局安装,因为现在您不确定是否需要它们?您是否曾更新过一个软件包以获取其中一个项目中的代码,但却发现更新的软件包使另一个项目中的代码停止工作?我们 Build 了packrat来解决这些问题 . 使用packrat使您的R项目更多:隔离:为一个项目安装新的或更新的包不会破坏您的其他项目,反之亦然 . 那是因为packrat为每个项目提供了自己的私有包库 . 便携式:轻松将项目从一台计算机传输到另一台计算机,甚至跨越不同的平台 . Packrat使您可以轻松安装项目所依赖的软件包 . 可重复:Packrat会记录您所依赖的确切软件包版本,并确保无论您走到哪里都可以安装这些版本 .

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

Related