느린 R 기능의 속도를 높이기 위해 C 코드를 작성하는 방법은 어디서 배울 수 있습니까?
R과 함께 사용하기 위해 C 코드를 작성하는 방법을 배울 수 있는 가장 좋은 자료는 무엇입니까?저는 Extensions의 시스템과 외국어 인터페이스 섹션에 대해 알고 있지만, 그것이 꽤 어렵다는 것을 알게 되었습니다.R과 함께 사용하기 위해 C 코드를 작성하기 위한 좋은 리소스(온라인 및 오프라인 모두)는 무엇입니까?
명확하게 말하자면, 저는 C 코드를 쓰는 법을 배우고 싶지 않고, R과 C를 더 잘 통합하는 방법을 배우고 싶습니다.예를 들어, C 정수 벡터에서 R 정수 벡터(또는 그 반대)로 변환하거나 C 스칼라에서 R 벡터로 변환하는 방법은 무엇입니까?
글쎄요, 출처를 사용하세요, 루크! --- R 자체는 연구할 수 있는 많은 (매우 효율적인) C 코드를 가지고 있고, Cran은 수백 개의 패키지를 가지고 있으며, 일부는 신뢰하는 작가의 패키지입니다.그것은 연구하고 적응할 수 있는 실제 테스트된 예를 제공합니다.
하지만 조쉬의 의심대로, 저는 C++과 Rcpp 쪽으로 더 기울었습니다.그것은 또한 많은 예를 가지고 있습니다.
편집: 도움이 되는 두 권의 책이 있었습니다.
- 첫 번째는 Venables와 Ripley의 "S 프로그래밍"입니다. 비록 그것이 치아에서 길어지고 있지만(그리고 몇 년 동안 2판에 대한 소문이 있었습니다).그 당시에는 단순히 다른 것이 없었습니다.
- Chambers의 "데이터 분석용 소프트웨어"의 두 번째는 훨씬 더 최신이고 훨씬 더 좋은 R 중심적 느낌을 가지고 있습니다. 그리고 R을 확장하는 것에 대한 두 개의 장입니다.C와 C++ 둘 다 언급됩니다.게다가, 존은 내가 다이제스트로 한 일 때문에 나를 갈기갈기 찢어버려, 그것만으로도 입장료를 지불할 가치가 있어요.
즉, John은 R 객체와 C++ 객체(Rcpp를 통해) 간의 일치가 매우 자연스럽다고 생각하기 때문에 Rcpp(그리고 기여)를 점점 더 좋아하고 있습니다. Reference Classes는 거기에 도움이 됩니다.
편집 2: 해들리의 다시 초점을 맞춘 질문과 함께, 저는 당신이 C++을 고려할 것을 강력히 촉구합니다.C와 관련된 진부한 헛소리가 너무 많습니다. 매우 지루하고 피할 수 있습니다.Rcpp 소개 Vignett을 확인해 보십시오.또 다른 간단한 예는 10%의 차이를 걱정하는 대신(래드포드 닐 사례 중 하나에서) C++로 80배 증가할 수 있다는 것을 보여주는 이 블로그 게시물입니다.
편집 3: C++ 오류에 부딪힐 수 있다는 점에서 복잡성이 있습니다. 부드럽게 말하자면, 더듬기가 어렵습니다.하지만 Rcpp를 확장하기보다는 그냥 사용하기 위해, 당신은 그것이 거의 필요하지 않습니다.이러한 비용은 부인할 수 없지만, 코드가 단순해지고 상용판이 줄어들며 PROTECT/UNPROTECT가 없고 메모리 관리가 되지 않는 등의 이점이 있습니다.Doug Bates는 어제 C++와 Rcpp가 C++. YMMV 등을 쓰는 것보다 R을 쓰는 것에 훨씬 더 가깝다고 말했습니다.
해들리,
당신은 분명히 C 코드와 비슷한 C++ 코드를 작성할 수 있습니다.
C보다 C++가 더 복잡하다는 당신의 말을 이해합니다.이것은 만약 여러분이 모든 것을 마스터하고 싶다면, 객체, 템플릿, STL, 템플릿 메타 프로그래밍 등입니다. 대부분의 사람들은 이런 것들을 필요로 하지 않고 단지 다른 사람들에게 의존할 수 있습니다.Rcpp의 구현은 매우 복잡하지만 냉장고가 어떻게 작동하는지 모른다고 해서 문을 열고 신선한 우유를 가져올 수 없다는 것을 의미하지는 않습니다.
R에 대한 당신의 많은 기여에서 인상적인 것은 R이 다소 지루하다는 것입니다(데이터 조작, 그래픽, 문자열 조작 등).R의 내부 C API로 더 많은 놀라움에 대비하세요.이것은 매우 지루합니다.
저는 가끔 R-exts 또는 R-ints 설명서를 읽습니다.도움이 됩니다.하지만 대부분의 경우, 제가 정말로 무언가에 대해 알고 싶을 때, 저는 R 소스와 예를 들어 작성된 패키지의 소스로 들어갑니다.사이먼 (보통 그곳에는 배울 것이 많습니다.
Rcpp는 API의 이러한 지루한 측면을 없애도록 설계되었습니다.
당신은 몇 가지 예를 바탕으로 당신이 더 복잡하고 난독화된 것 등을 스스로 판단할 수 있습니다.이 함수는 C API를 사용하여 문자 벡터를 만듭니다.
SEXP foobar(){
SEXP ab;
PROTECT(ab = allocVector(STRSXP, 2));
SET_STRING_ELT( ab, 0, mkChar("foo") );
SET_STRING_ELT( ab, 1, mkChar("bar") );
UNPROTECT(1);
}
Rcpp를 사용하면 다음과 같은 함수를 작성할 수 있습니다.
SEXP foobar(){
return Rcpp::CharacterVector::create( "foo", "bar" ) ;
}
또는:
SEXP foobar(){
Rcpp::CharacterVector res(2) ;
res[0] = "foo" ;
res[1] = "bar" ;
return res ;
}
더크가 말했듯이, 몇 개의 비네트에는 다른 예들이 있습니다.우리는 또한 사람들이 각각 코드의 매우 특정한 부분을 테스트하고 다소 자기 설명적이기 때문에 보통 우리의 단위 테스트를 향해 사람들을 가리킵니다.
저는 분명히 여기에 편향되어 있지만, R의 C API를 배우는 대신 Rcpp에 대해 익숙해지는 것을 추천하고, Rcpp에 대해 명확하지 않거나 할 수 없는 것 같으면 메일링 리스트에 올 것을 권장합니다.
어쨌든, 세일즈 피치는 끝입니다.
결국 어떤 종류의 코드를 작성하고 싶은지에 따라 모든 것이 달라질 것입니다.
로마인
@해들리: 안타깝게도, 저는 당신이 C++를 시작하는 데 도움이 될 구체적인 자원을 염두에 두고 있지 않습니다.저는 스콧 마이어스의 책(이펙트 C++, 더 효과적 C++ 등)에서 그것을 배웠지만, 이것들은 실제로 입문서라고 부를 수 있는 것은 아닙니다.
거의 독점적으로 사용합니다.인터페이스를 호출하여 C++ 코드를 호출합니다.규칙은 충분히 쉽습니다.
- C++ 함수는 R 개체를 반환해야 합니다.모든 R 개체는 SEXP입니다.
- C++ 함수는 0과 65 사이의 R 개체를 입력으로 사용합니다(다시 SEXP).
- 외부 "C" 또는 Rcpp가 정의하는 RcppExport 별칭을 사용하여 C 링크로 선언해야 합니다(그렇지는 않지만 나중에 저장할 수 있습니다).
그래서 .Call 함수는 일부 헤더 파일에서 다음과 같이 선언됩니다.
#include <Rcpp.h>
RcppExport SEXP foo( SEXP x1, SEXP x2 ) ;
.cpp 파일에서 다음과 같이 구현되었습니다.
SEXP foo( SEXP x1, SEXP x2 ){
...
}
Rcpp를 사용하는 R API에 대해 더 이상 알 필요가 없습니다.
대부분의 사람들은 Rcpp에서 숫자 벡터만 다루기를 원합니다.Numeric Vector 클래스에서 이 작업을 수행합니다.숫자 벡터를 만드는 몇 가지 방법이 있습니다.
R에서 전달하는 기존 개체:
SEXP foo( SEXP x_) {
Rcpp::NumericVector x( x_ ) ;
...
}
::를 사용하여 지정된 값을 사용하여 정적 함수 생성:
Rcpp::NumericVector x = Rcpp::NumericVector::create( 1.0, 2.0, 3.0 ) ;
Rcpp::NumericVector x = Rcpp::NumericVector::create(
_["a"] = 1.0,
_["b"] = 2.0,
_["c"] = 3
) ;
지정된 크기:
Rcpp::NumericVector x( 10 ) ; // filled with 0.0
Rcpp::NumericVector x( 10, 2.0 ) ; // filled with 2.0
일단 벡터를 갖게 되면, 가장 유용한 것은 그것으로부터 하나의 요소를 추출하는 것입니다.이 작업은 연산자 []에서 0 기반 인덱싱을 사용하여 수행되므로, 예를 들어 숫자 벡터의 합계 값은 다음과 같습니다.
SEXP sum( SEXP x_ ){
Rcpp::NumericVector x(x_) ;
double res = 0.0 ;
for( int i=0; i<x.size(), i++){
res += x[i] ;
}
return Rcpp::wrap( res ) ;
}
하지만 Rcpp 설탕을 사용하면 이제 훨씬 더 잘 할 수 있습니다.
using namespace Rcpp ;
SEXP sum( SEXP x_ ){
NumericVector x(x_) ;
double res = sum( x ) ;
return wrap( res ) ;
}
전에 말했듯이, 그것은 당신이 어떤 종류의 코드를 작성하기를 원하는지에 달려 있습니다.Rcpp에 의존하는 패키지에서 사람들이 무엇을 하는지 알아보고, vignets를 확인하고, 유닛 테스트를 확인하고, 메일링 리스트로 우리에게 다시 옵니다.우리는 항상 기꺼이 도와드립니다.
@jbremnant:맞아요.Rcpp 클래스는 RAII 패턴에 가까운 것을 구현합니다.Rcpp 개체가 생성되면 생성자는 기본 R 개체(SEXP)가 가비지 수집기로부터 보호되도록 적절한 조치를 취합니다.소멸자가 보호를 철회합니다.이것은 Rcpp 소개 vignett에 설명되어 있습니다.기본 구현은 R API 함수 R_PreserveObject 및 R_ReleaseObject에 의존합니다.
실제로 C++ 캡슐화로 인한 성능 저하가 있습니다.우리는 인라인 등을 사용하여 이것을 최소한으로 유지하려고 노력합니다.벌금이 적고, 코드를 작성하고 유지하는 데 걸리는 시간 측면에서 이득을 고려할 때, 그것은 그다지 관련성이 없습니다.
Rcpp 클래스 Function에서 R 함수를 호출하는 것은 C api로 eval을 직접 호출하는 것보다 느립니다.왜냐하면 우리는 R 오류를 캡처하고 C++의 표준 try/catch를 사용하여 처리할 수 있도록 TryCatch 블록에 함수 호출을 랩하기 때문입니다.
대부분의 사람들은 벡터(특히 Numeric Vector)를 사용하기를 원하며, 이 클래스에서는 패널티가 매우 작습니다.example/ConvolveBenchmarks 디렉토리에는 R-exts의 악명 높은 컨볼루션 함수의 여러 변형이 포함되어 있으며 vignet은 벤치마크 결과를 가지고 있습니다.Rcpp는 R API를 사용하는 벤치마크 코드보다 더 빠르게 만드는 것으로 나타났습니다.
언급URL : https://stackoverflow.com/questions/4106174/where-can-i-learn-how-to-write-c-code-to-speed-up-slow-r-functions
'programing' 카테고리의 다른 글
Angular2 경로에서 Angular2 경로의 매개 변수를 가져오는 방법은 무엇입니까? (0) | 2023.06.10 |
---|---|
게시할 때 TypeScript 파일을 포함하는 방법은 무엇입니까? (0) | 2023.06.10 |
날짜와 시간이 아닌 시간만 저장하는 방법은 무엇입니까? (0) | 2023.06.10 |
기본적으로 Visual Studio를 관리자로 실행하려면 어떻게 해야 합니까? (0) | 2023.05.31 |
java를 사용하여 mongoDB에 이미지를 삽입하는 방법은 무엇입니까? (0) | 2023.05.31 |