Элегантный способ проверить отсутствующие пакеты и установить их?
Кажется, я делюсь большим количеством кода с соавторами в эти дни. Многие из них являются начинающими / промежуточными пользователями R и не понимают, что им нужно устанавливать пакеты, которых у них еще нет.
Есть ли элегантный способ позвонить installed.packages()
, сравните это с теми, которые я загружаю и устанавливаю, если отсутствует?
36 ответов
Да. Если у вас есть список пакетов, сравните его с выводом из 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)
Иначе:
Если вы поместите свой код в пакет и сделаете их зависимостями, они будут автоматически установлены при установке пакета.
У Дэйсона К. и у меня есть пакет pacman, который может сделать это красиво. Функция p_load
в пакете это делает. Первая строка просто для того, чтобы убедиться, что pacman установлен.
if (!require("pacman")) install.packages("pacman")
pacman::p_load(package1, package2, package_n)
Вы можете просто использовать возвращаемое значение 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
,
Многие из приведенных выше ответов (и дубликатов этого вопроса) основаны на 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
отдельно для каждого пакета он пропускает весь вектор неустановленных пакетов только один раз.
Вот та же самая функция, но с диалоговым окном, которое спрашивает, хочет ли пользователь установить недостающие пакеты
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)
}
}
}
if (!require('ggplot2')) install.packages('ggplot2'); library('ggplot2')
"ggplot2" - это пакет. Он проверяет, установлен ли пакет, если он не установлен, то устанавливает его. Затем он загружает пакет независимо от того, какую ветку он принял.
Почти все ответы здесь полагаются на (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
будет DESCRIPTION
файл в file.path(.libPaths(), pkg)
, так что быстрая и грязная проверка file.exists(file.path(.libPaths(), pkg, 'DESCRIPTION')
.
Это решение будет использовать символьный вектор имен пакетов и попытаться загрузить их или установить их, если загрузка не удалась. Это зависит от обратного поведения 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" ) )
Хотя ответ Шейна действительно хорош, для одного из моих проектов мне нужно было автоматически удалять выходные сообщения, предупреждения и устанавливать пакеты. Мне наконец удалось получить этот скрипт:
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)
}
}
# 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)
Использование packrat
так что разделяемые библиотеки точно такие же и не меняют окружение других.
С точки зрения элегантности и лучшей практики, я думаю, что вы в корне ошибаетесь. посылка packrat
был разработан для этих вопросов. Он разработан RStudio Хэдли Уикхем. Вместо них приходится устанавливать зависимости и, возможно, испортить кому-то систему окружения packrat
использует свой собственный каталог и устанавливает все зависимости для ваших программ в свои и не затрагивает чью-либо среду.
Packrat - это система управления зависимостями для R.
Зависимости пакета R могут быть разочаровывающими. Приходилось ли вам когда-либо использовать метод проб и ошибок, чтобы выяснить, какие R-пакеты вам нужно установить, чтобы заставить работать чужой код, а затем навсегда оставить эти пакеты глобально установленными, потому что теперь вы не уверены, нужны ли они вам?? Вы когда-нибудь обновляли пакет, чтобы заставить код в одном из ваших проектов работать, только чтобы обнаружить, что из-за обновленного пакета код в другом проекте перестает работать?
Мы создали пакет для решения этих проблем. Используйте packrat, чтобы сделать ваши R проекты более:
- Изолированный: установка нового или обновленного пакета для одного проекта не нарушит другие ваши проекты, и наоборот. Это потому, что packrat предоставляет каждому проекту свою собственную библиотеку пакетов.
- Переносимость: легко переносить свои проекты с одного компьютера на другой, даже на разные платформы. Packrat позволяет легко устанавливать пакеты, от которых зависит ваш проект.
- Воспроизводимые: Packrat записывает точные версии пакетов, от которых вы зависите, и гарантирует, что именно эти версии будут установлены везде, где бы вы ни находились.
Вы можете просто использовать setdiff
функция, чтобы получить пакеты, которые не установлены, а затем установить их. В приведенном ниже примере мы проверяем, ggplot2
а также Rcpp
пакеты устанавливаются перед их установкой.
unavailable <- setdiff(c("ggplot2", "Rcpp"), rownames(installed.packages()))
install.packages(unavailable)
В одну строку вышеприведенное можно записать так:
install.packages(setdiff(c("ggplot2", "Rcpp"), rownames(installed.packages())))
Это цель пакета rbundler: предоставить способ управления пакетами, установленными для конкретного проекта. Прямо сейчас пакет работает с функциональностью devtools для установки пакетов в каталог вашего проекта. Функциональность похожа на пакет Ruby.
Если ваш проект представляет собой пакет (рекомендуется), тогда все, что вам нужно сделать, это загрузить 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.
Предстоящая версия 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/
Похоже, это особенно хорошо отвечает первоначальной проблеме ОП:
Многие из них являются начинающими / промежуточными пользователями R и не понимают, что им нужно устанавливать пакеты, которых у них еще нет.
Конечно.
Вам необходимо сравнить "установленные пакеты" с "желаемыми пакетами". Это очень близко к тому, что я делаю с CRANberries, так как мне нужно сравнить "сохраненные известные пакеты" с "известными на данный момент пакетами", чтобы определить новые и / или обновленные пакеты.
Так что-то вроде
AP <- available.packages(contrib.url(repos[i,"url"])) # available t repos[i]
чтобы получить все известные пакеты, выполните симуляцию вызова установленных в данный момент пакетов и сравните их с заданным набором целевых пакетов.
Я использую следующую функцию для установки пакета, если 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, которое не может быть гарантировано все время!
Сегодня я наткнулся на две удобные функции, предоставляемые пакетом rlang, а именно, и .
На странице справки (выделено мной):
Эти функции проверяют, установлены ли пакеты с минимальными побочными эффектами. Если он установлен, пакеты будут загружены, но не прикреплены.
is_installed()
не взаимодействует с пользователем. Он просто возвращаетTRUE
или жеFALSE
в зависимости от того, установлены ли пакеты.На интерактивных сессиях
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.
Создано 25 марта 2022 г. пакетом reprex (v2.0.1)
Следующая простая функция работает как брелок:
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)
}
(не мой, нашел это в Интернете некоторое время назад и использовал его с тех пор. не уверен в первоначальном источнике)
Думаю, я внесу тот, который я использую:
testin <- function(package){if (!package %in% installed.packages())
install.packages(package)}
testin("packagename")
Я реализовал функцию установки и загрузки необходимых 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);
Довольно простой.
pkgs = c("pacman","data.table")
if(length(new.pkgs <- setdiff(pkgs, rownames(installed.packages())))) install.packages(new.pkgs)
source("https://bioconductor.org/biocLite.R")
if (!require("ggsci")) biocLite("ggsci")
Используя семейный подход и анонимную функцию, вы можете:
- Попробуйте прикрепить все перечисленные пакеты.
- Установка отсутствует (с помощью
||
ленивая оценка) только. - Попытайтесь снова присоединить те, которые отсутствовали на шаге 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
Относительно вашей основной цели "установить библиотеки, которых у них еще нет." И независимо от использования " 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")
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 }
Я понимаю, что это старый вопрос, но большая часть технологий в R была значительно улучшена за последние месяцы и годы для решения именно этой проблемы. Общепринятый и современный подход к совместному использованию кода с зависимостями пакетов, которые могут быть или не быть установлены на компьютере сотрудника или целевом компьютере, заключается в использовании пакета ( «» — сокращение от «Воспроизводимая среда»), который был впервые создан. доступен как0.8.0
в конце октября 2019 года. Версия
Этот пакет очень помогает сотрудникам R в совместном использовании кода, пакетов (их точной версии, их зависимостей и их версий) и даже в отслеживании точной версии R, которая использовалась для сборки и выполнения кода в проекте R.
Чтобы использовать его, обычно первоначальный программист создает проект R в R Studio/Posit, а затем инициализирует проект с помощью команды
- Создает библиотеку пакетов для конкретного проекта внутри проекта вместо использования общей/глобальной библиотеки или библиотек (например,
). В рамках этого шага также создается каталог, содержащий некоторые настройки и файлы, которые большинство пользователей обычно не беспокоят, поскольку они позаботятся об этом за вас. - Создает файл .
Файл, который представляет собой профиль проекта R для конкретного проекта, который настраивает R для использования библиотеки конкретного проекта, созданной на шаге 1, при открытии проекта. - Создает файл блокировки, называемый
в домашнем каталоге проекта, где регистрируются сведения обо всех пакетах и версиях, используемых проектом, — именно это делает использование наиболее привлекательным вариантом для совместного использования кода с зависимостями пакета и пакета/версии.
После инициализации среды проекта с помощью
На этом этапе первоначальный программист может поделиться проектом с другими соавторами (в идеале это делается через GitHub, Bitbucket, Azure DevOps и т. д.). Когда новые сотрудники открывают проект R, они просто вводят команду
Это отличный рабочий процесс, поскольку он гарантирует, что все пользователи будут работать с одной и той же версией пакетов, которую использовал первоначальный разработчик. Без , возможно, что у соавтора в его глобальной библиотеке установлена совершенно другая версия пакета R, и она может функционировать иначе, чем исходный пакет разработчика. Это может привести к поломке кода или, что еще хуже, к запуску, но в результате к другому результату, возможно, без ведома конечных пользователей.
Как прекрасно описано в виньетке «Введение в renv» , пользователи получают преимущества, обеспечивая изоляцию пакетов , воспроизводимость среди пользователей и сред, а также переносимость .
И последнее замечание: если
Удачи и приятного сотрудничества!
Я использую следующее, которое проверит, установлен ли пакет и обновлены ли зависимости, затем загружает пакет.
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, ])
}
Неужели никто не используетlibrarian
?
# install.packages("librarian") # install if you do not have it
librarian::shelf(Rcpp, tidyverse/ggplot2)
Как вы можете видеть, его даже можно установить с github без кавычек, что делает его более последовательным. Кроме того, он может устанавливать пакеты биопроводников.
Позвольте мне разделить немного безумия:
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)))
Вот мой код для этого:
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)
Есть новый пакет (я соразработчик),
Require
, который должен быть частью воспроизводимого рабочего процесса, что означает, что функция выдает одни и те же выходные данные при первом запуске или последующих запусках , т. е. конечное состояние является одним и тем же независимо от начального состояния. Следующее устанавливает все отсутствующие пакеты (я включаю
require = FALSE
чтобы строго ответить на исходный вопрос ... обычно я оставляю это значение по умолчанию, потому что обычно хочу, чтобы они загружались в путь поиска).
Эти две строки находятся вверху каждого сценария, который я пишу (при необходимости настраивая выбор пакета), что позволяет использовать сценарий любому в любых условиях (включая отсутствие каких-либо или всех зависимостей).
if (!require("Require")) install.packages("Require")
Require::Require(c("ggplot2", "Rcpp"), require = FALSE)
Таким образом, вы можете использовать это в своем сценарии или передать кому-либо.