R 패키지 다운로드, 오프라인(offline) 설치 (Windows, CentOS)

2021. 11. 9. 18:48[개발] 지식/R

R은 처음이었다.

전달받은 R 모델을 Python으로 처리해야 하는 상황이었는데, 이를 위해서는 rpy2라는 파이썬 모듈을 사용해야 했다. 그런데 rpy2 모듈은 R 기능이 직접 구현된 것이 아닌라, OS에 설치된 R의 인터페이스 역할만 할 뿐이었다.

결국 rpy2를 사용하기 위해 API 서버가 위치한 CentOS 7 서버에 R을 설치해야 했는데.. 늘 그렇듯이 인터넷이 안되는 망이어서 큰 난관이 예상되었다. 결국 어찌어찌 설치에는 성공하였지만, 정말 험난한 과정이었다.

오프라인 환경에서 CentOS에 R 패키지를 다운로드 및 설치 하는 방법을 알아보자.

패키지 설치파일 다운로드

의존성(dependency) 패키지 조회

예를들어 caret 이라는 패키지를 설치하고 싶은경우, 해당 패키지에 필요한 의존성 패키지들이 먼저 설치가 되어 있어야 caret을 설치할 수 있다. (저는 caret 이 필요했으므로 이것을 기준으로 설명합니다)

로컬이 아닌 온라인에서 설치하는 경우 의존성 패키지 설치까지 알아서 해주지만, 오프라인으로 설치하는 경우에는 의존성 패키지 소스파일까지 일일이 받아서 설치해야 한다.

이를 위해 package_name 에 설치하고자 하는 패키지 명을 넣으면, 이와 관련된 모든 의존성 패키지를 모두 리턴해주는 함수를 아래와 같이 생성한다.

getDependencies <- function(package_name){
    packages_list <- unlist(
        tools::package_dependencies(packages = package_name, db = available.packages(),
                                    which = c("Depends", "Imports"),
                                    recursive = TRUE))
    packages_list <- union(package_name, packages_list)

    return(packages_list)
}

그리고 아래와 같이 호출하면

result = getDependencies("caret")

다음과 같은 charatervector를 얻을 수 있다.

[1] "caret"        "ggplot2"      "lattice"      "e1071"        "foreach"      "grDevices"    "methods"
[8] "ModelMetrics" "nlme"         "plyr"         "pROC"         "recipes"      "reshape2"     "stats"
[15] "stats4"       "utils"        "withr"        "graphics"     "class"        "proxy"        "codetools"
[22] "iterators"    "digest"       "glue"         "grid"         "gtable"       "isoband"      "MASS"
[29] "mgcv"         "rlang"        "scales"       "tibble"       "Rcpp"         "data.table"   "dplyr"
[36] "ellipsis"     "generics"     "gower"        "ipred"        "lifecycle"    "lubridate"    "magrittr"
[43] "Matrix"       "purrr"        "tidyr"        "tidyselect"   "timeDate"     "vctrs"        "stringr"
[50] "R6"           "pillar"       "rpart"        "survival"     "nnet"         "prodlim"      "splines"
[57] "farver"       "labeling"     "munsell"      "RColorBrewer" "viridisLite"  "stringi"      "fansi"
[64] "pkgconfig"    "colorspace"   "cli"          "crayon"       "utf8"         "KernSmooth"   "lava"
[71] "tools"        "future.apply" "progressr"    "numDeriv"     "SQUAREM"      "future"       "globals"
[78] "parallel"     "listenv"      "parallelly"

이 함수를 이용하여 caret 패키지와 의존성 패키지들의 소스파일을 destdir 에 저장한다.

download.packages(pkgs = getDependencies("caret"), destdir = "C:/R/packages_both", type = "source")
  • download.packages : package 소스파일을 다운받을 수 있는 명령어
  • type :
    • source : 컴파일이 안된 소스파일 (install시 컴파일 후 설치가 진행됨)
    • both : binary가 있으면 binary 파일을 받고 없으면 source 파일을 받는다
    • mac.binary : mac에서 설치할 수 있는 binary
    • win.binary : windows에서 설치할 수 있는 binary
  • destdir : 다운로드 할 경로

source로 받았다면 tar.gz 파일들을 받앗을 것이다.

옵션에 대해 자세히 알고 싶다면 아래 링크를 참조하자.

install.packages function - RDocumentation

패키지 설치

설치파일 복사

다운로드를 다 받았으면, 설치할 머신(컴퓨터)에 복사해서 넣는다.

CentOS 7가 설치된 Oracle Cloude VM에 테스트하였으며, 경로는 /home/opc/R/packagestar.gz 들을 복사했다.

그리고 R을 실행하고(R은 설치되어 있다고 가정) 아래 명령어를 실행해서 working directory를 설정한다.

setwd("/home/opc/R/packages")

설정된 working directory 확인하려면 아래와 같이 한다.

getwd()

설치 (install)

만약 설치하고자 하는 패키지가 하나라면 (tar.gz 가 하나라면) 다음과 같이 설치한다.

ex) codetools_0.2-18.tar 패키지를 단독으로 설치

install.packages("codetools_0.2-18.tar", repos=NULL, type="source")

여기서 repos=NULL 옵션은 repository를 원격을 바라보지 않고 로컬에서 찾겠다는 뜻이다.

하지만 대부분의 경우 의존성(dependency → 제일 짜증남)이 엮여있기 때문에 여러개의 파일들을 다운받았을 것이다. 여러 패키지 파일 한번에 설치하려면 아래와 같이 패턴을 주어서 설치한다.

install.packages(list.files(pattern = "*.tar.gz"), repos=NULL, type="source")

한번에 끝났다면 운이 좋은 것이다.

R은 의존성(dependency) 관계를 모르기 때문에, 설치된 패키지도 있을 것이며 의존성 패키지가 먼저 설치되지 않아 설치가 실패한것들도 있을 것이다.

그래서 위의 명령어(install.packages...)를 모든 패키지가 설치될 때까지 계속 반복해주어야 한다.

아마 설치 시작할때 아래처럼 에러가 발생했었을 것이다.

아래 에러가 발생안할때까지 반복해서 설치해주자.

ERROR: dependencies ‘foreach’, ‘recipes’ are not available for package ‘caret’

의존성 정보를 줄 수 있는 방법이 있나 살펴보았지만, 원격 repository에서 설치할때는 의존성 패키지들을 알아서 찾는데 로컬에서 파일로 설치하는 방법은 찾지 못했다. (만약 방법이 있다면 알려주시면 감사하겠습니다)

나름 자동화를 하고 싶어서 나름대로 아래 코드를 짜보았는데, 테스트는 못했기 때문에 적당히 참고만 하길 바란다. 테스트할 때쯤에 이미 모든 패키지가 다 설치가 되어 버려서 검증은 포기했다. (너무 지쳐서)

installAllDependenciesPackages <- function(pkgs){

  pkgNames <- vector()
    for(pkgNameList in strsplit(pkgs, "_")){
    print(pkgNameList[1])
      pkgNames <- append(pkgNames, pkgNameList[1])
    }

  notInstalledPkgs <- pkgs[!(pkgNames %in% installed.packages()[, "Package"])]
  if (!length(notInstalledPkgs)){
    return ("Finish")
  }

  for(pkg in notInstalledPkgs){
    print(pkg)
    paste(pkg, "install will be started..")
    install.packages(pkg, repos=NULL, type="source", INSTALL_opts="--no-lock")
    paste(pkg, "install is completed..")
  }

  installAllDependenciesPackages(pkgs)

}

아래와 같이 호출한다.

installAllDependenciesPackages(list.files(pattern="*.tar.gz"))

조금 무식한 방법이긴 한데, 내용을 간략하게 설명하자면:

  1. tar.gz 파일 리스트를 모두 넘겨준다.
  2. 넘겨진 파일리스트에서 패키지명만 잘라낸 뒤, 설치된 패키지 목록과 비교한다.
  3. 만약 모든 패키지가 설치되어 있다면 종료한다.
  4. 하나라도 설치되어 있지 않다면, 설치되지 않은 패키지들을 루프돌면서 설치한다.
  5. 의존성 때문에 전부 설치 안되었을 수 있기 때문에 다시 재귀호출한다.

결론은 이 함수는 써보지 못했다.

다음으로 넘어가자.

Error 발생 케이스

00LOCK

반복 설치 중 아래와 같은 오류를 만났다.

ERROR: failed to lock directory ‘/usr/lib64/R/library’ for modifying
Try removing ‘/usr/lib64/R/library/00LOCK-codetools’

설치를 하다보면 종종 발생하는 에러인데 windows에서도 발생한 적이 있다.

windows에서는 해당 폴더를 삭제하고 다시 진행해서 해결했다.

하지만 아래와 같이 INSTALL_opts 옵션을 줘서 해결할 수도 있다.

install.packages("codetools_0.2-18.tar.gz", repos=NULL, type="source", INSTALL_opts="--no-lock")

또는 아래 명령어를 실행해서 lock을 풀어준다.

options("install.lock"=FALSE)

설치를 완료했다면, 전부 설치되었는지 확인할 필요가 있다.

아래 명령어를 실행하면 설치된 패키지 리스트를 변수에 담아준다.

ip <- as.character(installed.packages()[,1])

그리고 해당 변수를 입력하면 출력된다.

ip

icu4c download failed

이것 때문에도 좀 스트레스 많이 받았다.

caret 패키지 의존성 중에 stringi 라는 것이 있었는데, stringi 설치 중 아래와 같은 에러가 발생했다.

checking whether the ICU data library can be downloaded... downloading the ICU data library (icudt)
output path: icu69/data/icu4c-69_1-data-bin-l.zip
trying URL 'https://raw.githubusercontent.com/gagolews/stringi/master/src/icu69/data/icu4c-69_1-data-bin-l.zip'
Error in download.file(paste(href, fname, set = ""), icudtzipfname, mode = "wb"): cannot open URL 'https://raw.githubusercontent.com/gagolews/stringi/master/src/icu69/data/icu4c-69_1-data-bin-l.zip'output path: icu69/data/icu4c-69_1-data-bin-l.zip

대충 내용을 보면, ICU data library가 없어서 icu4c-69_1-data-bin-l.zip를 다운로드 받으려고 했는데, 인터넷이 안되니 접속불가여서 발생한 에러이다.

처음에는 icu4c를 CentOS 에 따로 설치하려고 하였으나, gcc 버전 업을 해야했고, 난 또다시 rpm 의존성 지옥에 빠져버려서 다시 문서를 찾아보니.. configure.vars 옵션으로 해결이 가능하다고 한다.

먼저 위의 에러에 나온 링크에 접속해서 icu4c-69_1-data-bin-l.zip 를 다운받는다. 아 물론 stringi 버전에 따라 icu4c 버전도 파일도 다를 수 있다. (각자 에러메세지를 참조한다)

zip 파일을 받았다면 타겟 머신에 넣어두고 아래처럼 경로를 지정해서 설치를 진행하면 된다. (극혐..)

install.packages(list.files(pattern = "stringi_1.7.5.tar.gz"), repos=NULL, type="source", configure.vars="ICUDT_DIR=/home/opc/R/icu69")

여기서는 에러 케이스를 2가지만 적었지만, 사실 자잘한 걸림돌들이 많이 있었다. 하지만 크게 중요한 것들이 아니기에 내용에 추가하진 않았다. 조금이나마 삽질을 덜 수 있기를 바란다.

Ref.

[R] R 패키지 오프라인 설치를 위한 방법(on CentOS) - 1. 의존성 패키지 한번에 받기

R패키지 설치시 00LOCK 폴더 오류해결법

Install ICU4C From Source

Release ICU 69.1 · unicode-org/icu

<