최근 Rcpp와 C++의 Eigen 을 활용해서 개발을 진행하였다. 지난 포스트에서처럼 sourceCpp()
를 활용해서 로컬에서 어느 정도 개발을 마치고, 서버에서 이를 실행하려고 했는데..
에러가 발생하였다..
위 에러를 해결하기 위해 이것저것 찾아본 결과, 현재 R 프로젝트를 패키지로 빌드해야한다는 결론에 도달하였다. 하지만, 처음 해보는 R 패키지 빌드 역시 험난한 과정이었으니..!
이번 글에서는 간단한 R 패키지를 개발해보면서 R 패키지 빌드 및 설치 과정을 단계별로 정리하려고 한다.
이번 글의 경우,
usethis
패키지를 활용하며 아래 글에 기초해서 작성되었습니다.
R Packages (2e) by Hadley Wickham and Jenny Bryan - 2. The Whole Game따라서
usethis
패키지가 익숙하지 않으시다면 위 링크에 있는 글을 먼저 읽고 따라해주세요!
이번 글에서는 1) 차원에 대한 identity matrix 를 출력하는 함수와 2) 행렬 덧셈을 수행하는 함수를 포함한 R 패키지를 개발할 것이다.
위 과정을 단계별로 정리해보면 다음과 같다.
본격적인 시작에 앞서, devtools
라이브러리를 import 했는지 확인해야한다. 만약에 이를 빠뜨렸다면 library(devtools)
로 먼저 devtools
라이브러리를 불러오자.
다음으로, 이번 패키지에서는 RcppEigen 을 사용하기 때문에 아래 구문을 실행하자.
use_rcpp_eigen()
src
디렉토리 추가)Eigen
으로 행렬 연산을 수행하는 함수 작성하기Eigen
을 활용해서 다음과 같이 행렬 연산을 수행하는 함수를 작성하자.print_identity_matrix
는 차원에 대한 identity matrix 를 출력하는 함수이고, matrix_addition
은 행렬 덧셈을 수행하는 함수이다.#include <Rcpp.h>
#include <iostream>
#include <cmath>
//[[Rcpp::depends(RcppEigen)]]
#include <RcppEigen.h>
using namespace Rcpp;
// [[Rcpp::export]]
void print_identity_matrix(size_t p){
Eigen::MatrixXd identityMatrix = Eigen::MatrixXd::Identity(p, p);
std::cout << "Identity matrix with " << pow(p, 2) << " elements" << std::endl;
std::cout << identityMatrix << std::endl;
}
// [[Rcpp::export]]
Eigen::MatrixXd matrix_addition(Eigen::MatrixXd A, Eigen::MatrixXd B){
Eigen::MatrixXd rslt_mat = A+B;
return rslt_mat;
}
usethis
패키지의 use_r()
함수를 사용해보자. 예를 들어, show_identity_matrix
라는 이름의 R 함수를 추가하고 싶다면 아래와 같이 R 콘솔에 입력하자.use_r("show_identity_matrix")
# show_identity_matrix.R
#' Test Rcpp Eigen using the identity matrix
#'
#' @param p
#'
#' @return
#' @export
#'
#' @examples
#' show_identity_matrix(5)
show_identity_matrix <- function(p){
print_identity_matrix(p)
}
# test_eigen_matrix_additon.R
#' Test Rcpp Eigen using the matrix addition
#'
#' @param A
#' @param B
#'
#' @return A matrix
#' @export
#'
#' @examples
#' A <- matrix(seq(1,4), nrow=2)
#' B <- matrix(seq(5,8), nrow=2)
#' test_eigen_matrix_addition(A, B)
test_eigen_matrix_addition <- function(A, B){
rslt_mat = matrix_addition(A,B)
return(rslt_mat)
}
💡 R 함수를 선언할 때, 위 주석 부분을 꼭 지키자! 위 주석 부분이 있어야 Roxygen을 통해서 해당 함수가
NAMESPACE
에 정상적으로 등록될 수 있고, 해당 함수에 대한 문서(.Rd
)도 정상적으로 생성된다.
load_all()
src/
에 c++ 파일에 대한 object file(*.o
)이 생성되었음을 확인할 수 있다.importFrom(Rcpp,evalCpp)
useDynLib(regexcite, .registration=TRUE)
위 첫번째 줄의 코드는 Rcpp이 정상적으로 import 되지 않은 상황에서 Rcpp 함수가 호출되는 에러 상황을 방지한다.다음으로, 두번째 줄의 코드는 컴파일된 c++ 파일의 object 파일이 R 함수에서 호출될 수 있도록 연결(link)하는 역할을 담당하다.
R
폴더 아래 {패키지명}-package.R
이라는 파일을 만들자. 우리 예제에서는 regexcite-package.R
라는 파일을 만들자## usethis namespace: start
#' @importFrom Rcpp evalCpp
#' @useDynLib regexcite, .registration = TRUE
## usethis namespace: end
NULL
@useDynLib
뒤에 패키지명을 자신이 정한 패키지명을 넣으면 된다.💡
Rcpp
외 다른 패키지를 import 하여 해당 패키지의 함수를 사용하는 경우에도@importFrom
에 해당 내용을 추가해야한다.
- 예시:
stats
패키지의runif
함수를 호출하고 싶다면#' @importFrom stats runif
를 위 파일에 추가해야한다.- 추가적으로, 특정 패키지에서 사용하려는 함수가 여러개라면 공백을 사이에 두고, 함수명을 나열하면 된다.
#' @importFrom stats lm sd quantile
load_all()
을 다시 불러보면 NAMESPACE
파일에 우리가 추가하려는 내용이 포함되었음을 확인할 수 있다!load_all()
로 NAMESPACE
파일 업데이트가 안 된다면 R 콘솔에 check()
를 입력하여, check
함수를 호출해서 확인할 수도 있다.결과적으로, show_identity_matrix
함수와 test_eigen_matrix_addition
함수가 정상적으로 출력됨을 확인할 수 있다!!
이제 최종 단계로 R 패키지를 .tar.gz
파일로 빌드하자.
빌드에 앞서 최종 R 프로젝트 형상을 확인해보면 아래와 같다.
├── .gitignore
├── .Rbuildignore
├── .Rhistory
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── man
│ ├── strsplit1.Rd
│ ├── show_identity_matrix.Rd
│ ├── test_eigen_matrix_addition.Rd
├── NAMESPACE
├── R
│ ├── strsplit1.R
│ ├── show_identity_matrix.R
│ ├── test_eigen_matrix_addition.R
│ ├── regexcite-package.R
│ ├── RcppExports.R
├── regexcite.Rproj
├── src
│ ├── .gitignore
│ ├── test_eigen.cpp
│ ├── RcppExports.cpp
(Mac OS 기준) 터미널에 R CMD BUILD regexcite
라고 치면 regexcite_{버전}.tar.gz
라는 파일이 생성된다.
R CMD build regexcite
는 regexcite
프로젝트 디렉토리의 부모 디렉토리에서 실행해야한다는 점을 주의하자.이제 R에서 regexcite
패키지를 설치하고, 행렬 연산 함수를 호출해보자!
regexcite
패키지가 설치되지 않았음을 먼저 확인해보자.regexcite
패키지를 삭제할 수 있다.remove.packages("regexcite")
regexcite
패키지를 설치하자. install.packages(
"{regexcite 패키지 tar.gz 파일 경로}",
repos=NULL,
type="source"
)
최종적으로, 설치된 regexcite
패키지를 import하여, 목표 함수를 호출하는 것까지 성공하였다!
velog 에서 이미지 크기 조절이 불가하여, 실행 결과 캡쳐 화면이 조금 너저분하게 보이는 점 양해 부탁드립니다...
-> 혹시 velog 본문에서 이미지 크기 조절을 하는 방법을 아신다면 댓글로 공유 부탁드립니다 😭😭
피드백은 언제나 환영입니다! 혹시 잘못된 부분을 발견하셨거나 궁금하신 점이 있다면 댓글창에 남겨주세요! 그럼 다음 포스트에서 또 만나요!