Элегантный способ проверить отсутствующие пакеты и установить их? - PullRequest
288 голосов
/ 03 ноября 2010

Кажется, я делюсь большим количеством кода с соавторами в эти дни. Многие из них являются новичками / пользователями среднего уровня и не понимают, что им нужно устанавливать пакеты, которых у них еще нет.

Существует ли элегантный способ вызова installed.packages(), сравните его с теми, которые я загружаю и устанавливаю в случае отсутствия?

Ответы [ 26 ]

249 голосов
/ 03 ноября 2010

Да. Если у вас есть список пакетов, сравните его с выводом 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)

В противном случае:

Если вы поместите свой код в пакет и сделаете их зависимостями, то они будут автоматически установлены при установке пакета.

191 голосов
/ 09 ноября 2013

Дейсон К. и у меня есть пакет pacman , который может сделать это прекрасно. Функция p_load в пакете делает это. Первая строка просто для того, чтобы убедиться, что pacman установлен.

if (!require("pacman")) install.packages("pacman")
pacman::p_load(package1, package2, package_n)
57 голосов
/ 09 ноября 2013

Вы можете просто использовать возвращаемое значение require:

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

Я использую library после установки, потому что он выдаст исключение, если установка не удалась или пакет не может быть загружен по какой-либо другой причине. Вы делаете это более надежным и многократно используемым:

dynamic_require <- function(package){
  if(eval(parse(text=paste("require(",package,")")))) return True

  install.packages(package)
  return eval(parse(text=paste("require(",package,")")))
}

Недостатком этого метода является то, что вы должны передавать имя пакета в кавычках, чего вы не делаете для реального require.

17 голосов
/ 09 ноября 2013

Это решение будет использовать символьный вектор имен пакетов и попытаться загрузить их или установить их, если загрузка не удалась. Для этого он использует возвращаемое поведение require, потому что ...

require возвращает (невидимо) логическое указание, доступен ли требуемый пакет

Поэтому мы можем просто посмотреть, смогли ли мы загрузить требуемый пакет, а если нет, установить его с зависимостями. Итак, учитывая символьный вектор пакетов, которые вы хотите загрузить ...

foo <- function(x){
  for( i in x ){
    #  require returns TRUE invisibly if it was able to load package
    if( ! require( i , character.only = TRUE ) ){
      #  If package was not able to be loaded then re-install
      install.packages( i , dependencies = TRUE )
      #  Load package after installing
      require( i , character.only = TRUE )
    }
  }
}

#  Then try/install packages...
foo( c("ggplot2" , "reshape2" , "data.table" ) )
15 голосов
/ 14 января 2012

Хотя ответ Шейна действительно хорош, для одного из моих проектов мне нужно было удалить выходные сообщения, предупреждения и установить пакеты автоматически . Мне наконец удалось получить этот сценарий:

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)
    }
}
13 голосов
/ 01 сентября 2016
if (!require('ggplot2')) install.packages('ggplot2'); library('ggplot2')

"ggplot2" - это пакет.Он проверяет, установлен ли пакет, если он не установлен, то устанавливает его.Затем он загружает пакет независимо от того, какую ветку он принял.

13 голосов
/ 20 июня 2017

Многие ответы выше (и дубликаты этого вопроса) полагаются на 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)
        }
    }
}
8 голосов
/ 16 февраля 2014
# List of packages for session
.packages = c("ggplot2", "plyr", "rms")

# Install CRAN packages (if not already installed)
.inst <- .packages %in% installed.packages()
if(length(.packages[!.inst]) > 0) install.packages(.packages[!.inst])

# Load packages into session 
lapply(.packages, require, character.only=TRUE)
6 голосов
/ 03 декабря 2012

Это цель пакета rbundler : предоставить способ управления пакетами, установленными для конкретного проекта.Прямо сейчас пакет работает с функциональностью devtools для установки пакетов в каталог вашего проекта.Функциональность аналогична связке Ruby .

Если ваш проект представляет собой пакет (рекомендуется), то все, что вам нужно сделать, это загрузить rbundler и связать пакеты.Функция bundle будет проверять файл DESCRIPTION вашего пакета, чтобы определить, какие пакеты нужно объединить.

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

Теперь пакеты будут установлены в каталоге .Rbundle.

Если вашПроект не является пакетом, поэтому вы можете подделать его, создав файл DESCRIPTION в корневом каталоге вашего проекта с полем Зависит, в котором перечислены пакеты, которые вы хотите установить (с дополнительной информацией о версии):

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

Вот репозиторий github для проекта, если вы хотите внести свой вклад: rbundler .

5 голосов
/ 03 ноября 2010

Конечно.

Вам необходимо сравнить «установленные пакеты» с «желаемыми пакетами». Это очень близко к тому, что я делаю с CRANberries , так как мне нужно сравнить «сохраненные известные пакеты» с «известными на данный момент пакетами», чтобы определить новые и / или обновленные пакеты.

Так что-то вроде

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

чтобы получить все известные пакеты, выполните симуляцию вызова для установленных в данный момент пакетов и сравните их с заданным набором целевых пакетов.

...