2012-02-28 17 views
5

まず、この問題は特定の問題を解決しようとするものではありません。 Rの新人として、より効率的なコードとコード作成手順を作成する作業も行っています。この問題の背景には、さまざまなプログラミング方法やスタイルについての視点があります。以下はコードビルドプロセスと組み込み関数

は何かをコーディングするための3つの方法があります。ここで

まずデータ例である:

stackexample <- c(52,50,45,49.5,50.5,12,10,14,11.5,12,110,108,106,101,104) 
dim(stackexample)<- c(5,3) 

方法1:任意のオブジェクト

ertimesIVCV1 <- function (x) 
{ (solve(var(log((x[-nrow(x),])/(x[-1,])))))%*% 
    ((1+(log(x[1,]/(x)[nrow(x),])))^(1/nrow(x))-1)} 

ertimesIVCV1(stackexample) 

を定義せずに機能して計算を行います方法2:関数内のオブジェクトを定義し、それらのオブジェクトを操作する

ertimesIVCV2 <- function (x) 
{ IVCV <- solve(var(log((x[-nrow(x),])/(x[-1,])))); 
    retsexcess <- (1+(log(x[1,]/(x)[nrow(x),])))^(1/nrow(x))-1; 
    IVCV%*%retsexcess} 

ertimesIVCV2(stackexample) 

方法3:複数の関数を定義し、したがって、すべてが同じ答え生産機能

IVCV <- function (x) {solve(var(log((x[-nrow(x),])/(x[-1,]))))} 
retsexcess <- function(x) (1+(log(x[1,]/(x)[nrow(x),])))^(1/nrow(x))-1 
ertimesIVCV3 <- function (x) {IVCV(x)%*%retsexcess(x)} 

ertimesIVCV3(stackexample) 

「などの要約」でこれらの関数を呼び出す:

  [,1] 
[1,] 1.4430104 
[2,] -0.1365155 
[3,] 11.8088378 

いますが、3つの異なるアプローチを見ることができるようにします。

最適な数の組み込み関数が存在するのですか、または常にすべての数学を明示的にリストする必要がありますか?関数内のいくつのレベルの関数が最適ですか?どちらの方法も計算速度が優れていますか?これに親指のルールがありますか?どのようにこれにアプローチしますか?すべてのコメントや提案やリンクは歓迎され、ありがとう!

目標は、時間効率であればライ

+1

http://stackoverflow.com/q/4406873/210673、特に@ GavinSimpsonの回答を参照してください。 – Aaron

答えて

6

IMHOの場合、コードを書くとき、特に初心者の場合は、速度効率がの最後のになるはずです。代わりに、主な焦点は、シンプルさ、可読性、モジュール性についてです。私を間違って読んではいけません。効率は素晴らしいことです。必要になったときにコードを高速化する方法はたくさんありますが、それだけでは優先事項ではありません。

だから、主にスタイルに関するヒントを紹介します。具体的には、私のバージョンのコードは次のようになります。私はあなたのコードが何を計算しているのか分からないので、意味のある変数名を使用してそれを打破しようと努力しました。

IVCV <- function(stack) { 

## This function computes [...] IVCV stands for [...] 
## Inputs: 
## - stack: a matrix where each column [...] 
## Output: a matrix [...] 

    n <- nrow(stack) # stack size 
    stack.ratios <- stack[-n, ]/stack[-1, ] 
    log.ratios <- log(stack.ratios) 
    ivcv   <- solve(var(log.ratios)) 

    return(ivcv) 
} 

ExcessReturn <- function(stack) { 

## This function computes [...] IVCV stands for [...] 
## Inputs: 
## - stack: a matrix where each column [...] 
## Output: a matrix [...] 

    n <- nrow(stack) # stack size 
    total.ratio <- stack[1, ]/stack[n, ] 
    excess.return <- (1 + log(total.ratio))^(1/n) - 1 

    return(excess.return) 
} 

ExcessReturnTimesIVCV <- function(stack) { 

## This function computes [...] IVCV stands for [...] 
## Inputs: 
## - stack: a matrix where each column [...] 
## Output: a vector [...] 

    return(IVCV(stack) %*% ExcessReturn(stack)) 
} 

)はい、小さな機能にコードを分割します。可読性、柔軟性、保守性に優れています。また、単体テストが容易になり、基本的なコードごとにテストを設計することができます。

2)機能の本体内にその説明/入力/出力に関するコメントを含めることによって、機能を文書化する。このようにして、機能が作成された後、ユーザはその機能のプリントアウトの一部としてその説明を見ることができる(例えば、GUIにExcessReturnTimesIVCVと入力するだけ)。

3)複雑さを複数のステートメントに分割します。今、あなたの3つの提案のすべては理解するのが難しく、それぞれの行には多くのことが起こります。ステートメントは簡単なことを行う必要がありますので、簡単に読むことができます。より多くのオブジェクトを作成すると、プロセスが遅くなることはほとんどなく、デバッグがはるかに簡単になります。

4)あなたのオブジェクト名は、コードを明確にするための鍵です。それらを適切に選択し、一貫した構文を使用してください。私は自分の関数の名前にUpperCamelCaseを使用し、ほとんどの他のオブジェクトでは小文字の単語をドットで区切ります。

5)コメントを入力します。特に3)と4)はコードを明確にするには不十分です。私の例では、変数nを使用することを選択しました。私は、変数名が説明的でなければならないという勧告に反対しましたが、コードを少し軽くして、stack[-n, ]/stack[-1, ]のような表現を素敵な対称性にすることでした。 nは悪い名前なので、その意味を説明するコメントを付けます。関数が実際に何をしているのか分かっていれば、コードにコメントを追加することもできます。

6)一貫性のある構文ルールを使用してください。ほとんどの場合、可読性が向上します。あなたはここで何を使うべきかについて異なる意見を聞くでしょう。一般に、最良のアプローチは1つありません。最も重要なことは選択肢を作ってそれに固執することです。だからここに私の提案があります:

a)行ごとに1つのセミコロンはありません。一貫した間隔およびくぼみ(タブなし)。

b)私はバイナリ演算子の周りにコンマの後にスペースを入れます。読みやすさを助けるために余分なスペースを使って整列させています。

c)一貫性のあるブレース:ブロックを定義するために中括弧を使用する方法に注意してください。そうしないと、スクリプトモードで問題が発生する可能性があります。 R Infernoのセクション8.1.43(参考にしてください)

幸運を祈る!

6

は、提供例との答えが「気に誰が?」です。関数呼び出しのオーバーヘッドは効率を決定するものではありません。おそらく、ユーザーの理解やコードを維持する能力など、他の問題に焦点を当てるべきです。

require(rbenchmark) 
benchmark(replications=100, ver1= ertimesIVCV1(stackexample), 
ver2=ertimesIVCV2(stackexample), 
ver3 = ertimesIVCV3(stackexample)) 
# ------------------ 
    test replications elapsed relative user.self sys.self user.child sys.child 
1 ver1   100 0.030 1.000000  0.03  0   0   0 
2 ver2   100 0.030 1.000000  0.03  0   0   0 
3 ver3   100 0.031 1.033333  0.03  0   0   0 
4

DWinには同意しません(ただし実際には別のスピンを入れています)。目標が、時間効率がの場合、いくつかのケースがあります。一度何かしているのなら、私は「誰が気にする?」と同意します。おそらく方法1または2で、あなたが思っているものは何でもいいと思います。

方法3の利点は再現性です。同じコードを2回以上入力すると効率が低下します。それを関数に入れて、型入力を省くと、特にミスタイピングの可能性があります。私はあなたが既に関数に物事を入れることについて話しているのを見ていますが、あなたのIVCV関数はユーティリティや他の関数として便利でしょうか?もしそうでなければ、それを気にしないでください。

プロジェクトが大きくなるほど、それ自身の機能を持つ断片に分割する方が良いでしょう。これにより、組織化、デバッグ、および変更をよりスムーズに行うことができます。

関連する問題