34

require と :: の使用に関する最近の質問は、R でプログラミングするときにどのプログラミング スタイルを使用するか、およびそれらの長所/短所は何かという疑問を提起しました。ソース コードを参照したり、ネットを参照したりすると、さまざまなスタイルが表示されていることがわかります。

私のコードの主な傾向:

  • 重いベクトル化私はインデックス (およびネストされたインデックス) をよく使用します。その結果、コードがわかりにくくなることがありますが、通常は他のソリューションよりもはるかに高速です。例:x[x < 5] <- 0代わりにx <- ifelse(x < 5, x, 0)

  • クリーンアップが必要な一時オブジェクトでメモリが過負荷になるのを避けるために、関数をネストする傾向があります。特に大規模なデータセットを操作する関数では、これは大きな負担になる可能性があります。例:y <- cbind(x,as.numeric(factor(x)))代わりにy <- as.numeric(factor(x)) ; z <- cbind(x,y)

  • たとえば、コードを一度だけ使用する場合でも、多くのカスタム関数を作成します。sapply。_ 横になったままになるオブジェクトを作成することなく、読みやすくなると思います。

  • ベクトル化はよりクリーン (かつ高速) であると考えているため、ループは絶対に避けます。

しかし、これについては意見が分かれていることに気付きました。一部の人々は、私の「Perl」プログラミング方法 (または「Lisp」でさえも、私のコード内でこれらすべての括弧が飛んでいます) と呼ぶものから遠ざかる傾向があります。そこまで行かないけど)。

R での優れたコーディング手法は何だと思いますか?

あなたのプログラミング スタイルは何ですか?また、その長所と短所をどのように見ていますか?

4

4 に答える 4

21

私が何をするかは、コードを書いている理由によって異なります。研究 (本業) のためにデータ分析スクリプトを作成している場合、機能するものの、数か月後または数年後でも読みやすく理解できるものが必要です。計算時間はあまり気にしません。lapply等によるベクトル化。難読化につながる可能性がありますが、これは避けたいと思います。

lapplyそのような場合、たとえば適切な無名関数を構築するためにフープをジャンプする必要がある場合は、反復プロセスにループを使用します。ifelse()少なくとも私の考えでは、その呼び出しの意図はサブセット + 置換バージョンよりも理解しやすいため、最初の箇条書きで使用します。私のデータ分析では、必ずしも計算時間よりも物事を正しく行うことに関心があります。大きな仕事を実行できる週末や夜は、オフィスにいないときが常にあります。

あなたの他の弾丸のために; 非常に些細でない限り、呼び出しをインライン化/ネストしない傾向があります。手順を明確に説明すると、コードが読みやすくなり、バグが含まれる可能性が低くなります。

私は常にカスタム関数を作成します。特に、関数に相当するコードをループなどで繰り返し呼び出す場合はそうです。このようにして、メインのデータ分析スクリプトからコードを独自の.Rファイルにカプセル化しました。これにより、分析の意図と分析の実行方法を分離することができます。そして、その機能が有用であれば、他のプロジェクトなどで使用するために持っています.

パッケージのコードを書いている場合、データ分析と同じ態度 (慣れ親しみ) から始めて、機能することがわかっているものを取得し、計算時間を改善したい場合にのみ最適化を行います。

私が避けるようにしていることの 1 つは、コーディングの対象が何であれ、コーディングするときに賢すぎることです。結局のところ、私は自分が思っているほど賢くはありません。物事をシンプルにしていれば、賢くなろうとしているときほど頻繁に失敗することはありません。

于 2010-12-10T09:44:25.297 に答える
11

.R私は、概念的に 1 つのことを行うコードのさまざまなチャンクに対して(スタンドアロン ファイルで) 関数を記述します。これにより、物事は短くて甘くなります。traceback()どの関数がエラーを生成したかがわかるため、デバッグがやや簡単であることがわかりました。

私も、絶対に必要な場合を除いて、ループを避ける傾向があります。for()ループを使うと少し汚い気がします。:) 私はすべてをベクトル化するか、apply ファミリを使用して実行することに非常に力を入れています。これは常にベスト プラクティスとは限りません。特に、適用やベクトル化に精通していない別の人にコードを説明する必要がある場合はなおさらです。

requirevsの使用に関しては、::両方を使用する傾向があります。特定のパッケージの関数が 1 つだけ必要な場合は 経由::で使用しますが、複数の関数が必要な場合はパッケージ全体をロードします。パッケージ間で関数名が競合する場合は、覚えて使用するようにしています::

達成しようとしているすべてのタスクの関数を見つけようとします。私の前に誰かがそれを考え、私が思いつくよりもうまく機能する機能を作ったと信じています。これはうまくいくこともあれば、うまくいかないこともあります。

私はそれを理解できるように自分のコードを書こうとします。これは、私が達成しようとしていることのアイデアに何らかの形で従うように、多くのコメントを付けてコードのチャンクを構築することを意味します。関数が進行するにつれて、オブジェクトを上書きすることがよくあります。これにより、特に関数の後半でこれらのオブジェクトを参照している場合に、タスクの透明性が保たれると思います。計算時間が私の忍耐力を超えたとき、私は速度について考えます。関数の終了に時間がかかりすぎて SO の閲覧を開始した場合は、それを改善できるかどうかを確認します。

コードの折りたたみと構文の色付けを備えた優れた構文エディター (私は Eclipse + StatET を使用しています) のおかげで、多くの頭痛の種が解消されたことがわかりました。

VitoshKa の投稿に基づいて、関数名には大文字の単語 (sensu Java) を使用し、変数には fullstop.delimited を使用することを追加します。関数の引数に別のスタイルを使用できることがわかりました。

于 2010-12-10T10:15:19.667 に答える
8

命名規則は、コードを読みやすくするために非常に重要です。R の S4 内部スタイルに触発されて、私が使用するものは次のとおりです。

  • グローバル関数とオブジェクトのキャメルケース (doSomething、getXyyy、upperLimit など)
  • 関数は動詞で始まります
  • エクスポートされず、ヘルパー関数は常に "." で始まります。
  • ローカル変数と関数はすべて小文字で "_" 構文 (do_something、get_xyyy) です。ローカルとグローバルを簡単に区別できるため、よりクリーンなコードになります。
于 2010-12-12T09:57:35.863 に答える
4

データ ジャグリングでは、少なくとも GROUP BY 平均などの基本的なことについては、できるだけ多くの SQL を使用するようにしています。私は R が大好きですが、別のパッケージに隠された別の機能を見つけるには、自分の研究戦略が十分ではなかったことを理解するのは楽しいだけではありません。私の場合、SQL の方言はそれほど変わらず、コードは本当に透過的です。ほとんどの場合、しきい値 (R 構文の使用を開始する時期) は直感的に発見できます。例えば

require(RMySQL)
# selection of variables alongside conditions in SQL is really transparent
# even if conditional variables are not part of the selection
statement = "SELECT id,v1,v2,v3,v4,v5 FROM mytable
             WHERE this=5
             AND that != 6" 
mydf <- dbGetQuery(con,statement)
# some simple things get really tricky (at least in MySQL), but simple in R
# standard deviation of table rows
dframe$rowsd <- sd(t(dframe))

そのため、ほとんどのユースケースでデータに SQL データベースを使用することをお勧めします。私もTSdbiを調べてリレーショナルデータベースに時系列を保存していますが、まだそれを判断することはできません.

于 2010-12-10T10:27:38.293 に答える