質問
Rで使用するためのCコードを書き込む方法を学ぶための最良のリソースは何ですか?私はについて知っています システムと外国語インターフェイス R拡張機能のセクションですが、私はそれがかなり難しいと思います。 Rで使用するCコードを作成するための優れたリソース(オンラインとオフラインの両方)は何ですか?
明確にするために、私はCコードの書き方を学びたくありません。たとえば、RとCをより良く統合する方法を学びたいと思います。たとえば、C整数ベクトルからR整数ベクトルに変換するにはどうすればよいですか(またはその逆)またはCスカラーからRベクトルまで?
解決
さて、古き良きがあります ソース、ルークを使用してください! --- R自体には多くの(非常に効率的な)Cコードが研究でき、Cranには何百ものパッケージがあり、一部は信頼できる著者からです。これは、研究と適応のための実際のテストされた例を提供します。
しかし、ジョシュが疑ったように、私はC ++にもっと傾いているので、 rcpp. 。また、多くの例があります。
編集: 私が役立つと思った2冊の本がありました:
- 最初のものはVenablesとRipley's」ですSプログラミング「歯の中で長くなっているにもかかわらず(そして長年にわたって第2版の噂がありました)。当時、他に何もありませんでした。
- チャンバーズの2番目のデータ分析のためのソフトウェア「これははるかに最近で、R-Centricの感触がはるかに優れています。R。CとC ++の両方が言及されている2つの章が言及されています。 ダイジェスト そのため、それだけで入場料の価値があります。
とはいえ、ジョンは好きになっています rcpp (そして貢献)彼はRオブジェクトとC ++オブジェクトの間の一致を見つけたとき(経由 rcpp)非常に自然であること - そして参照採学者はそこで助けます。
編集2: Hadleyの質問がある質問で、i 非常に強く C ++を考慮するように促してください。あなたがcと関係しているボイラープレートのナンセンスはたくさんあります---非常に退屈でそして 非常に回避できます. 。を見てください rcpp-introduction vignette. 。別の簡単な例は次のとおりです このブログ投稿 私が示すところでは、Radford Nealの例の1つで)10%の違いを心配する代わりに、私たちは得ることができます 8倍 C ++とともに増加します(もちろん、不自然な例です)。
編集3: C ++エラーに遭遇する可能性があるという点で複雑さがあります。しかし、ただ RCPPを使用します それを拡張するのではなく、あなたはそれをほとんど必要としないはずです。そして、これ 費用 否定できない、それはかなり覆われています 利点 より単純なコード、より少ないボイラープレート、保護/非プロテクト、メモリ管理などはありません。Pp。DougBatesは昨日、C ++とRCPPがC ++を書くよりもRを書くことに似ていると感じていると述べました。 YMMVなど。
他のヒント
ハドリー、
Cコードに似たC ++コードを絶対に記述できます。
C ++がCよりも複雑であることについてあなたが言うことを理解しています。これは、オブジェクト、テンプレート、STL、テンプレートメタプログラミングなどをすべて習得したい場合です。ほとんどの人はこれらのものを必要とせず、他の人に頼ることができますそれに。 RCPPの実装は非常に複雑ですが、冷蔵庫がどのように機能するかわからないからといって、ドアを開けて新鮮な牛乳をつかむことができないという意味ではありません...
Rへの多くの貢献から、私が私を襲ったのは、Rがやや退屈だと思うことです(データ操作、グラフィックス、文字列マニプラティオなど)。 Rの内部C APIでさらに多くの驚きに備えて準備してください。これは非常に退屈です。
時々、R-ExtsまたはR-Intsマニュアルを読みます。これは役立ちます。しかし、ほとんどの場合、私が本当に何かを知りたいとき、私はRソースに行き、EG Simonによって書かれたパッケージのソースにも入ります(通常、そこで学ぶべきことがたくさんあります)。
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で実行できないように見える場合はメーリングリストに来ます。
とにかく、セールスピッチの終わり。
最終的に書きたいコードの種類に依存すると思います。
ロマン
@Hadley:残念ながら、C ++の開始を支援する特定のリソースを念頭に置いていません。 Scott Meyersの本(効果的なC ++、より効果的なC ++など)からそれを拾い上げましたが、これらは実際には紹介と呼ばれるものではありません。
.Callインターフェイスをほぼ独占的に使用して、C ++コードを呼び出します。ルールは十分に簡単です:
- C ++関数はRオブジェクトを返す必要があります。すべてのrオブジェクトはsexpです。
- C ++関数は、入力として0〜65 Rオブジェクトを取得します(再びsexp)
- それは(実際にはそうではありませんが、後でこれを保存することができます)。 extern "c" または rcppexport RCPPが定義するエイリアス。
したがって、.call関数は、いくつかのヘッダーファイルでこのように宣言されます。
#include <Rcpp.h>
RcppExport SEXP foo( SEXP x1, SEXP x2 ) ;
このように.cppファイルに実装されています。
SEXP foo( SEXP x1, SEXP x2 ){
...
}
R APIについてRCPPを使用していることを知ることはそれほど多くありません。
ほとんどの人は、RCPPの数値ベクトルのみを扱いたいと考えています。これをnumericvectorクラスで行います。数値ベクトルを作成する方法はいくつかあります。
rから渡す既存のオブジェクトから:
SEXP foo( SEXP x_) {
Rcpp::NumericVector x( x_ ) ;
...
}
:: static関数の作成を使用して指定された値を使用してください。
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
その後、ベクトルができたら、最も便利なことは、1つの要素を抽出することです。これは、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に依存しているパッケージで人々が何をしているかを調べ、ビネット、ユニットテストを確認し、メーリングリストで私たちに戻ってきてください。私たちはいつも喜んで助けてくれます。
@Jbremnant:そうです。 RCPPクラスは、RAIIパターンに近いものを実装します。 RCPPオブジェクトが作成されると、コンストラクターは、基礎となるRオブジェクト(SEXP)がガベージコレクターから保護されていることを確認するために適切な手段を講じます。デストラクタは保護を撤回します。これはで説明されています rcpp-duction ビネット。基礎となる実装は、R API関数に依存しています r_preserveobject と R_RELEASEOBJECT
C ++カプセル化により、実際にパフォーマンスペナルティがあります。私たちはこれをインランスなどで最小限に抑えようとします...ペナルティは小さく、コードを書き込んで維持するのにかかる時間の点で利益を考慮すると、それはそれほど関連性がありません。
RCPPクラス関数からR関数を呼び出すことは、C APIを使用してevalを直接呼び出すよりも遅くなります。これは、予防策を講じて、関数呼び出しをトライキャッチブロックにラップして、Rエラーをキャプチャし、C ++例外を促進し、C ++で標準のトライ/キャッチを使用できるようにするためです。
ほとんどの人はベクター(特別な数字)を使用したいと考えており、このクラスではペナルティが非常に少ないです。例/ConvolveBenchmarksディレクトリには、R-Extsからの悪名高い畳み込み関数のいくつかのバリエーションが含まれており、ビネットにはベンチマークの結果があります。 RCPPは、R APIを使用するベンチマークコードよりも速くなることがわかります。