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

发布于 2024-09-30 11:35:02 字数 150 浏览 4 评论 0 原文

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

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

I seem to be sharing a lot of code with coauthors these days. Many of them are novice/intermediate R users and don't realize that they have to install packages they don't already have.

Is there an elegant way to call installed.packages(), compare that to the ones I am loading and install if missing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

像你 2024-10-07 11:35:03

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

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

    req <- 替代(require(x,character.only = TRUE))
    磅 <- c("plyr", "psych", "tm")
    sapply(lbs, function(x) eval(req) || {install.packages(x); eval(req)})
    
    plyr心理TM 
    真实真实真实 
    

Using lapply family and anonymous function approach you may:

  1. Try to attach all listed packages.
  2. Install missing only (using || lazy evaluation).
  3. Attempt to attach again those were missing in step 1 and installed in step 2.
  4. Print each package final load status (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 
    
涙—继续流 2024-10-07 11:35:03

我意识到这是一个较老的问题,但近几个月和几年来,R 中的许多技术已经得到了极大的改进,以解决这个确切的问题。处理具有可能安装或可能未安装在协作者计算机或目标计算机上的包依赖项的代码共享的普遍接受的现代方法是使用 renv(“renv”是“可复制环境”的缩写),最初作为 renv 提供 0.8.0 于 2019 年 10 月下旬发布。版本 1.0.0 于 2023 年 7 月 7 日正式发布,截至本文发布,当前 CRAN 版本为版本 1.0.2 >,于上个月 2023 年 8 月 15 日发布

该包极大地帮助 R 协作者共享代码、包(它们的确切版本及其依赖项和它们的版本),甚至跟踪用于在 R 中构建和执行代码的确切版本。 R 项目。

要使用它,初始程序员通常会在 R Studio/Posit 中创建一个 R 项目,然后使用命令 renv::init() 在项目内初始化 renv。执行此命令时,R 会执行以下操作:

  1. 在项目内创建项目特定包库,而不是使用通用/全局库强>或库(例如,.libPaths())。作为此步骤的一部分,renv 还会创建一个 renv 目录,其中包含一些大多数用户通常不会像 renv 那样关心的设置和文件为您处理这件事。
  2. 创建一个 .Rprofile 文件,该文件是特定于项目的 R 项目配置文件,用于将 R 配置为在以下情况下使用在步骤 1 中创建的项目特定库:你打开项目。
  3. 在项目主目录中创建一个名为 renv.lock 的锁定文件,该文件记录有关项目使用的所有包和版本的详细信息 - 这就是使用 renv 的原因与包和包/版本依赖项共享代码最有吸引力的选项。

使用 init() 命令初始化项目环境后,初始程序员将按照典型方式开发和编写代码,以通常的方式安装软件包(例如,只需输入 install.packages("PackageName ") 进入控制台)按照需要的方式进行。然而,这些包存储在项目库中,而不是任何全局库中。当初始程序员认为代码处于共享整个项目的令人满意的状态时,他只需发出 renv::snapshot() 命令,该命令只需更新在上面步骤 3 中创建的锁定文件,其中包含名称项目中使用的所有包的版本号、版本号等。

此时,初始程序员可以与其他协作者共享该项目(理想情况下,这是通过 GitHub 完成的,BitbucketAzure DevOps 等)。当任何新协作者打开 R 项目时,他们只需在控制台输入命令 renv::restore() 即可。这将安装项目中使用的每个包的完全相同版本(并且它将恢复到项目库而不是用户的全局包库中)。

这是一个出色的工作流程,因为它将确保所有用户都使用初始开发人员使用的相同版本的软件包。如果没有 renv,协作者可能会在其全局库中安装完全不同版本的 R 软件包,并且其功能可能与初始开发人员的软件包不同。这可能会导致代码被破坏,或者更糟糕的是,运行,但会导致不同的输出,最终用户可能不知道。

正如renv简介小插图中完美描述的那样, renv 通过确保包隔离、跨用户和环境的可重复性以及可移植性来为用户带来好处。 renv() 还具有其他一些好处,例如 R 包的缓存,这样在跨项目使用时就不必多次下载。 它也适用于 PythonPython 包。如果您还想确保环境的每个细节(包括操作系统和其他外部(对于 R/R Studio)依赖项)都已就位,您也可以通过将 renvDocker 镜像 完全容器化解决方案

最后一点:如果 renv 看起来与 packrat 类似,那是因为它在某种程度上确实如此。事实上,rev 的开发者首先尝试使用 packrat 构建一个可重现的环境包,但在与它的局限性作斗争后放弃并“推出了自己的”。但我认为它也好得多。好消息是,如果您已经在使用 packrat 并且想要升级到这个现代工具,您可以使用 renv::migrate() 命令轻松完成此操作!

祝你好运,合作愉快!

I realize this is an older question, but much of the technology in R has been greatly improved in recent months and years to address this exact issue. The generally accepted and modern approach for handling the sharing of code with package dependencies that may or may not be installed on a collaborator's computer or the target computer is to use the renv package ("renv" is short for "Reproducible Environment") which was first made available as renv 0.8.0 in late October of 2019. Version 1.0.0 was officially released on July 7, 2023, and, as of this post, the current CRAN release is Version 1.0.2, which was made available last month on August 15, 2023.

This package greatly aids R collaborators in sharing code, packages (their exact version and their dependencies and their versions), and even the tracking of the exact version of R that was used to build and execute code in an R project.

To use it, typically the initial programmer creates an R project in R Studio/Posit and then initializes renv within the project using the command renv::init(). When this is executed, R does the following:

  1. Creates an project specific package library within the project, rather than using the general/global library or libraries (e.g., .libPaths()). As part of this step, renv also creates an renv directory which contains some settings and files that most users don't generally bother with as renv takes care of this for you.
  2. Creates an .Rprofile file, which is a project-specific R project profile that configures R to use the project specific library created in step 1 when you open the project.
  3. Creates a lockfile, called renv.lock in the project home directory, which logs details about all the packages and versions used by the project -- this is what makes using renv the most attractive option for sharing code with package and package/version dependencies.

After initializing the project environment with the init() command, the initial programmer develops and writes code as typical, installing packages in the usual manner (e.g., by simply entering install.packages("PackageName") into the console) along they way as they are needed. These packages are stored into the project library, however, rather than any global library. When the initial programmer feels the code is in a satisfactory state to share the entire project, he simply issues the renv::snapshot() command which simply updates the lockfile created in step 3 above, with the names, version numbers, etc. of all the packages used in the project.

At this point the initial programmer can share the project with other collaborators (ideally this is done through GitHub, Bitbucket, Azure DevOps, etc.). When any new collaborators open the R project, they simply enter the command renv::restore() at the console. This will install the exact same version of every package used in the project (and it will be restored into the project library rather than the user's global package library).

This is an excellent workflow because it will ensure all users are working with the same version of the packages the initial developer used. Without renv, it's possible that a collaborator has a totally different version of an R package installed in their global library, and it may function differently from the initial developer's package. This could result in the code breaking, or worse yet, running, but resulting in different output, possibly unbeknownst to the end users.

As perfectly described on the Introduction to renv vignette, renv benefits users by ensuring package isolation, reproducibility across users and environments, and portability. renv() also enjoys some other benefits like caching of R packages so that they don't have to be downloaded multiple times when used across projects. It also works with Python and Python packages. If you also want to ensure that every detail of an enviroment—including the operating system and other external (to R/R Studio) dependencies—are in place, you can easily do so too by combining renv with a Docker image to fully containerize a solution!

One final note: if renv seems similar to packrat, that's because it is, somewhat. In fact the deverlopers of rev first attempted to build a reproducible environment package using packrat but gave up and "rolled their own" after struggling with its limitations. But it's vastly better too, I'd argue. The good news is, if you're already using packrat and want to upgrade to this modern tool, you can easily do so with the renv::migrate() command!

Good luck and happy collaborating!

隱形的亼 2024-10-07 11:35:03

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

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

I use the following which will check if package is installed and if dependencies are updated, then loads the package.

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, ])
}
感情废物 2024-10-07 11:35:03

这是我的代码:

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)

Here's my code for it:

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)
诗化ㄋ丶相逢 2024-10-07 11:35:03
library <- function(x){
  x = toString(substitute(x))
if(!require(x,character.only=TRUE)){
  install.packages(x)
  base::library(x,character.only=TRUE)
}}

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

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

This works with unquoted package names and is fairly elegant (cf. GeoObserver's answer)

裂开嘴轻声笑有多痛 2024-10-07 11:35:03

就我而言,我想要一个可以从命令行运行的单行程序(实际上是通过 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")

除了之前的解决方案之外,这里没有任何内容:

  • 我将其保留在一行中
  • 我硬编码了 < a href="https://www.rdocumentation.org/packages/utils/versions/3.4.3/topics/install.packages" rel="nofollow noreferrer">repos 参数(为了避免任何弹出窗口询问要使用的镜像)
  • 我懒得定义一个在其他地方使用的函数

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

In my case, I wanted a one liner that I could run from the commandline (actually via a Makefile). Here is an example installing "VGAM" and "feather" if they are not already installed:

R -e 'for (p in c("VGAM", "feather")) if (!require(p, character.only=TRUE)) install.packages(p, repos="http://cran.us.r-project.org")'

From within R it would just be:

for (p in c("VGAM", "feather")) if (!require(p, character.only=TRUE)) install.packages(p, repos="http://cran.us.r-project.org")

There is nothing here beyond the previous solutions except that:

  • I keep it to a single line
  • I hard code the repos parameter (to avoid any popups asking about the mirror to use)
  • I don't bother to define a function to be used elsewhere

Also note the important character.only=TRUE (without it, the require would try to load the package p).

一袭水袖舞倾城 2024-10-07 11:35:03

让我分享一些疯狂的事情:

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

Let me share a bit of madness:

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))) 
ゞ记忆︶ㄣ 2024-10-07 11:35:02

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

否则:

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

Yes. If you have your list of packages, compare it to the output from installed.packages()[,"Package"] and install the missing packages. Something like this:

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)

Otherwise:

If you put your code in a package and make them dependencies, then they will automatically be installed when you install your package.

心是晴朗的。 2024-10-07 11:35:02

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

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

Dason K. and I have the pacman package that can do this nicely. The function p_load in the package does this. The first line is just to ensure that pacman is installed.

if (!require("pacman")) install.packages("pacman")
pacman::p_load(package1, package2, package_n)
甜味拾荒者 2024-10-07 11:35:02

您可以只使用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 则不需要这样做。

You can just use the return value of require:

if(!require(somepackage)){
    install.packages("somepackage")
    library(somepackage)
}

I use library after the install because it will throw an exception if the install wasn't successful or the package can't be loaded for some other reason. You make this more robust and reuseable:

dynamic_require <- function(package){
  if(eval(parse(text=paste("require(",package,")")))) return(TRUE)
  
  install.packages(package)
  return(eval(parse(text=paste("require(",package,")"))))
}

The downside to this method is that you have to pass the package name in quotes, which you don't do for the real require.

玻璃人 2024-10-07 11:35:02

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

A lot of the answers above (and on duplicates of this question) rely on installed.packages which is bad form. From the documentation:

This can be slow when thousands of packages are installed, so do not use this to find out if a named package is installed (use system.file or find.package) nor to find out if a package is usable (call require and check the return value) nor to find details of a small number of packages (use packageDescription). It needs to read several files per installed package, which will be slow on Windows and on some network-mounted file systems.

So, a better approach is to attempt to load the package using require and and install if loading fails (require will return FALSE if it isn't found). I prefer this implementation:

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

which can be used like this:

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

This way it loads all the packages, then goes back and installs all the missing packages (which if you want, is a handy place to insert a prompt to ask if the user wants to install packages). Instead of calling install.packages separately for each package it passes the whole vector of uninstalled packages just once.

Here's the same function but with a windows dialog that asks if the user wants to install the missing 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)
        }
    }
}
无语# 2024-10-07 11:35:02
if (!require('ggplot2')) install.packages('ggplot2'); library('ggplot2')

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

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

"ggplot2" is the package. It checks to see if the package is installed, if it is not it installs it. It then loads the package regardless of which branch it took.

草莓酥 2024-10-07 11:35:02

TL;DR 您可以使用 find.package() 来实现此目的。

这里几乎所有的答案都依赖于(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 都会在 file 处有一个 DESCRIPTION 文件。 path(.libPaths(), pkg),因此快速而肮脏的检查是 file.exists(file.path(.libPaths(), pkg, 'DESCRIPTION')

TL;DR you can use find.package() for this.

Almost all the answers here rely on either (1) require() or (2) installed.packages() to check if a given package is already installed or not.

I'm adding an answer because these are unsatisfactory for a lightweight approach to answering this question.

  • require has the side effect of loading the package's namespace, which may not always be desirable
  • installed.packages is a bazooka to light a candle -- it will check the universe of installed packages first, then we check if our one (or few) package(s) are "in stock" at this library. No need to build a haystack just to find a needle.

This answer was also inspired by @ArtemKlevtsov's great answer in a similar spirit on a duplicated version of this question. He noted that system.file(package=x) can have the desired affect of returning '' if the package isn't installed, and something with nchar > 1 otherwise.

If we look under the hood of how system.file accomplishes this, we can see it uses a different base function, find.package, which we could use directly:

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

We can also look under the hood at find.package to see how it works, but this is mainly an instructive exercise -- the only ways to slim down the function that I see would be to skip some robustness checks. But the basic idea is: look in .libPaths() -- any installed package pkg will have a DESCRIPTION file at file.path(.libPaths(), pkg), so a quick-and-dirty check is file.exists(file.path(.libPaths(), pkg, 'DESCRIPTION').

戒ㄋ 2024-10-07 11:35:02

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

This solution will take a character vector of package names and attempt to load them, or install them if loading fails. It relies on the return behaviour of require to do this because...

require returns (invisibly) a logical indicating whether the required package is available

Therefore we can simply see if we were able to load the required package and if not, install it with dependencies. So given a character vector of packages you wish to load...

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" ) )
灼疼热情 2024-10-07 11:35:02

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

Although the answer of Shane is really good, for one of my project I needed to remove the ouput messages, warnings and install packages automagically. I have finally managed to get this script:

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

Use:

libraries <- c("ReadImages", "ggplot2")
for(library in libraries) 
{ 
    if(!UsePackage(library))
    {
        stop("Error!", library)
    }
}
绝情姑娘 2024-10-07 11:35:02
# 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)
# 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)
初熏 2024-10-07 11:35:02

RStudio 中的“Packrat”现已替换为“renv”。请参阅下面的评论。所以我的回答不再相关了。

------------------------------------------------ 
使用packrat使得共享库完全相同并且不改变别人的环境。

就优雅和最佳实践而言,我认为您从根本上采取了错误的方式。 packrat 包就是为了解决这些问题而设计的。它由 Hadley Wickham 的 RStudio 开发。 Packrat 使用自己的目录并在其中安装程序的所有依赖项,而不会影响某人的环境,而不必安装依赖项并可能弄乱某人的环境系统。

Packrat 是 R 的依赖管理系统。

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

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

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

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

'Packrat' has been replaced in RStudio by 'renv' now. See comment bellow. So my answer is no longer relavent.

------------------------------------
Use packrat so that the shared libraries are exactly the same and not changing other's environment.

In terms of elegance and best practice I think you're fundamentally going about it the wrong way. The package packrat was designed for these issues. It is developed by RStudio by Hadley Wickham. Instead of them having to install dependencies and possibly mess up someone's environment system, packrat uses its own directory and installs all the dependencies for your programs in there and doesn't touch someone's environment.

Packrat is a dependency management system for R.

R package dependencies can be frustrating. Have you ever had to use trial-and-error to figure out what R packages you need to install to make someone else’s code work–and then been left with those packages globally installed forever, because now you’re not sure whether you need them? Have you ever updated a package to get code in one of your projects to work, only to find that the updated package makes code in another project stop working?

We built packrat to solve these problems. Use packrat to make your R projects more:

  • Isolated: Installing a new or updated package for one project won’t break your other projects, and vice versa. That’s because packrat gives each project its own private package library.
  • Portable: Easily transport your projects from one computer to another, even across different platforms. Packrat makes it easy to install the packages your project depends on.
  • Reproducible: Packrat records the exact package versions you depend on, and ensures those exact versions are the ones that get installed wherever you go.

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

酷到爆炸 2024-10-07 11:35:02

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

This is the purpose of the rbundler package: to provide a way to control the packages that are installed for a specific project. Right now the package works with the devtools functionality to install packages to your project's directory. The functionality is similar to Ruby's bundler.

If your project is a package (recommended) then all you have to do is load rbundler and bundle the packages. The bundle function will look at your package's DESCRIPTION file to determine which packages to bundle.

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

Now the packages will be installed in the .Rbundle directory.

If your project isn't a package, then you can fake it by creating a DESCRIPTION file in your project's root directory with a Depends field that lists the packages that you want installed (with optional version information):

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

Here's the github repo for the project if you're interested in contributing: rbundler.

昇り龍 2024-10-07 11:35:02

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

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

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

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

You can simply use the setdiff function to get the packages that aren't installed and then install them. In the sample below, we check if the ggplot2 and Rcpp packages are installed before installing them.

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

In one line, the above can be written as:

install.packages(setdiff(c("ggplot2", "Rcpp"), rownames(installed.packages())))
趁微风不噪 2024-10-07 11:35:02

当前版本的 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 新手/中级用户,并且没有意识到他们必须安装他们尚未安装的软件包。

The current version of RStudio (>=1.2) includes a feature to detect missing packages in library() and require() calls, and prompts the user to install them:

Detect missing R packages

Many R scripts open with calls to library() and require() to load the packages they need in order to execute. If you open an R script that references packages that you don’t have installed, RStudio will now offer to install all the needed packages in a single click. No more typing install.packages() repeatedly until the errors go away!
https://blog.rstudio.com/2018/11/19/rstudio-1-2-preview-the-little-things/

This seems to address the original concern of OP particularly well:

Many of them are novice/intermediate R users and don't realize that they have to install packages they don't already have.

心的憧憬 2024-10-07 11:35:02

当然。

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

因此,请执行类似

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

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

Sure.

You need to compare 'installed packages' with 'desired packages'. That's very close to what I do with CRANberries as I need to compare 'stored known packages' with 'currently known packages' to determine new and/or updated packages.

So do something like

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

to get all known packages, simular call for currently installed packages and compare that to a given set of target packages.

羅雙樹 2024-10-07 11:35:02

今天,我偶然发现了 rlang 包提供的两个方便的函数,即 is_installed()check_installed()

帮助页面(添加了重点):

这些函数检查软件包的安装是否具有最小的副作用。如果安装,将加载包但不附加包。

is_installed() 不与用户交互。它只是返回 TRUEFALSE,具体取决于是否安装了软件包。

交互式会话中,check_installed() 询问用户是否安装缺少的软件包。如果用户接受,则会安装软件包[...]。如果会话是非交互式的或者用户选择不安装软件包,则当前评估将中止。

interactive()
#> [1] FALSE
rlang::is_installed(c("dplyr"))
#> [1] TRUE
rlang::is_installed(c("foobarbaz"))
#> [1] FALSE
rlang::check_installed(c("dplyr"))
rlang::check_installed(c("foobarbaz"))
#> Error:
#> ! The package `foobarbaz` is required.

reprex 包 (v2.0.1) 创建于 2022 年 3 月 25 日

Today, I stumbled on two handy function provided by the rlang package, namely, is_installed() and check_installed().

From the help page (emphasis added):

These functions check that packages are installed with minimal side effects. If installed, the packages will be loaded but not attached.

is_installed() doesn't interact with the user. It simply returns TRUE or FALSE depending on whether the packages are installed.

In interactive sessions, check_installed() asks the user whether to install missing packages. If the user accepts, the packages are installed [...]. If the session is non interactive or if the user chooses not to install the packages, the current evaluation is aborted.

interactive()
#> [1] FALSE
rlang::is_installed(c("dplyr"))
#> [1] TRUE
rlang::is_installed(c("foobarbaz"))
#> [1] FALSE
rlang::check_installed(c("dplyr"))
rlang::check_installed(c("foobarbaz"))
#> Error:
#> ! The package `foobarbaz` is required.

Created on 2022-03-25 by the reprex package (v2.0.1)

合约呢 2024-10-07 11:35:02

下面这个简单的函数就像一个魅力:(

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

不是我的,不久前在网上发现了这个,从那时起就一直在使用它。不确定原始来源)

The following simple function works like a charm:

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

(not mine, found this on the web some time back and had been using it since then. not sure of the original source)

安静 2024-10-07 11:35:02

如果 require("") 因找不到包错误而退出,我使用以下函数来安装包。它将查询 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 升级,但可能并不总是有保证!

I use following function to install package if require("<package>") exits with package not found error. It will query both - CRAN and Bioconductor repositories for missing package.

Adapted from the original work by 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)))
  }
}

Example:

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

PS: update.packages(ask = FALSE) & biocLite(character(), ask=FALSE) will update all installed packages on the system. This can take a long time and consider it as a full R upgrade which may not be warranted all the time!

吃→可爱长大的 2024-10-07 11:35:02

我想我会贡献我使用的一个:

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

Thought I'd contribute the one I use:

testin <- function(package){if (!package %in% installed.packages())    
install.packages(package)}
testin("packagename")
初见终念 2024-10-07 11:35:02

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

I have implemented the function to install and load required R packages silently. Hope might help. Here is the code:

# 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);
不寐倦长更 2024-10-07 11:35:02

非常基本的一个。

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

Quite basic one.

pkgs = c("pacman","data.table")
if(length(new.pkgs <- setdiff(pkgs, rownames(installed.packages())))) install.packages(new.pkgs)
墨小墨 2024-10-07 11:35:02

关于您的主要目标“安装他们还没有的库”,并且无论使用“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”)

Regarding your main objective " to install libraries they don't already have. " and regardless of using " instllaed.packages() ". The following function mask the original function of require. It tries to load and check the named package "x" , if it's not installed, install it directly including dependencies; and lastly load it normaly. you rename the function name from 'require' to 'library' to maintain integrity . The only limitation is packages names should be quoted.

require <- function(x) { 
  if (!base::require(x, character.only = TRUE)) {
  install.packages(x, dep = TRUE) ; 
  base::require(x, character.only = TRUE)
  } 
}

So you can load and installed package the old fashion way of R.
require ("ggplot2")
require ("Rcpp")

羁拥 2024-10-07 11:35:02
 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 }
 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 }
长发绾君心 2024-10-07 11:35:02
source("https://bioconductor.org/biocLite.R")
if (!require("ggsci")) biocLite("ggsci")
source("https://bioconductor.org/biocLite.R")
if (!require("ggsci")) biocLite("ggsci")
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文