web-dev-qa-db-ja.com

大規模なRプログラムを編成する方法は?

複雑なRプロジェクトに着手すると、私のスクリプトはすぐに長くて混乱します。

私のコードを常に楽しみたいと思うように、私が採用できるプラクティスは何ですか?私は次のようなことを考えています

  • ソースファイル内の関数の配置
  • 別のソースファイルに何かを分割するとき
  • マスターファイルにあるべきもの
  • 組織単位として機能を使用する(Rがグローバル状態へのアクセスを難しくすることを考えると、これが価値があるかどうか)
  • インデント/改行の練習。
    • 扱い({?
    • 1行または2行に)}のようなものを入れますか?

基本的に、大きなRスクリプトを整理するための経験則は何ですか?

157
Dan Goldstein

標準的な答えは、パッケージを使用することです。 R Extensionsの記述 マニュアルおよびWeb上のさまざまなチュートリアルを参照してください。

それはあなたに与えます

  • トピックごとにコードを整理する準自動方法
  • ヘルプファイルを作成することを強くお勧めします。
  • _R CMD check_による多くの健全性チェック
  • 回帰テストを追加する機会
  • 名前空間の手段と同様に。

コード上でsource()を実行するだけで、本当に短いスニペットで機能します。内部リポジトリ用の内部パッケージを作成できるので、それを公開する予定がない場合でも、それ以外はすべてパッケージに含める必要があります。

「編集方法」の部分については、セクション6の R Internals マニュアルに優れたRコーディング標準があります。 EmacsのESSモード でデフォルトを使用する傾向があります。

Update 2008-Aug-13:David Smithが Google R Style Guide についてブログに書きました。

69

独自のファイルにさまざまな機能を追加するのが好きです。

しかし、私はRのパッケージシステムが好きではありません。使いにくいです。

環境内にファイルの機能(他のすべての言語が「名前空間」と呼んでいるもの)を配置し、添付するための軽量の代替手段を好みます。たとえば、次のような関数の「util」グループを作成しました。

_util = new.env()

util$bgrep = function [...]

util$timeit = function [...]

while("util" %in% search())
  detach("util")
attach(util)
_

これはすべてファイル内にあります til.R 。ソースを取得すると、「util」環境が得られるため、util$bgrep()などを呼び出すことができます。しかし、さらにattach()呼び出しはbgrep()だけを呼び出し、そのようなものは直接動作します。これらのすべての関数を独自の環境に配置しなかった場合、それらはインタープリターのトップレベル名前空間(ls()が示すもの)を汚染します。

すべてのファイルがモジュールであるPythonのシステムをシミュレートしようとしていました。持っていた方が良いでしょうが、これは問題ないようです。

50
Brendan OConnor

特にプログラマーの場合、これは少し明白に聞こえるかもしれませんが、ここではコードの論理的および物理的単位について考える方法を示します。

これがあなたの場合かどうかはわかりませんが、Rで作業しているとき、大規模で複雑なプログラムを念頭に置いて始めることはめったにありません。通常、1つのスクリプトで開始し、コードを論理的に分離可能なユニットに分離します。多くの場合、関数を使用します。データ操作および視覚化コードは、独自の関数などに配置されます。また、そのような関数は、ファイルの1つのセクションにグループ化されます(上部のデータ操作、視覚化など)。最終的には、スクリプトを簡単に保守して欠陥率を下げる方法を考えたいと思います。

機能をどの程度細かく/粗くするかはさまざまであり、さまざまな経験則があります。 15行のコード、または「関数は名前で識別される1つのタスクを実行する必要があります」など。あなたのマイレージは異なります。 Rは参照による呼び出しをサポートしていないので、データフレームや同様の構造体を渡す必要がある場合、通常は関数を細かくしすぎます。しかし、これは私が最初にRで始めたときのいくつかのばかげたパフォーマンスの間違いに対する過剰な補償かもしれません。

論理ユニットを独自の物理ユニット(ソースファイルやパッケージなどのより大きなグループなど)に抽出する場合二つのケースがあります。まず、ファイルが大きくなりすぎて、論理的に無関係なユニット間をスクロールするのが面倒な場合。第二に、他のプログラムで再利用できる機能がある場合。通常は、データ操作関数などのグループ化されたユニットを別のファイルに配置することから始めます。その後、このファイルを他のスクリプトから取得できます。

関数をデプロイする場合は、パッケージについて考え始める必要があります。さまざまな理由で、Rコードを実稼働環境で展開したり、他の人が再利用したりすることはありません(簡単に言うと、組織文化は他の言語、パフォーマンスに関する懸念、GPLなどを好みます)。また、ソースファイルのコレクションを絶えず改良して追加する傾向があり、変更を加える際にはパッケージを扱いたくありません。したがって、この面の詳細については、Dirkのような他のパッケージ関連の回答を確認してください。

最後に、あなたの質問は必ずしもRに特定のものではないと思います。SteveMcConnellのCode Completeを読むことをお勧めします。

33
ars

ダークのアドバイスに同意します!私見、単純なスクリプトから文書化されたパッケージへのプログラムの編成は、Rでのプログラミングの場合、WordからTeX/LaTeXに切り替えて作成するようなものです。 Friedrich Leischによる非常に便利なRパッケージの作成:チュートリアルをご覧になることをお勧めします。

19
Paolo

私の簡潔な答え:

  1. 関数を慎重に記述し、一般的な十分な出力と入力を特定します。
  2. グローバル変数の使用を制限します。
  3. S3オブジェクトと、必要に応じてS4オブジェクトを使用します。
  4. 特に関数がC/Fortranを呼び出している場合は、関数をパッケージに入れます。

Rは実稼働環境でますます使用されているため、再利用可能なコードの必要性は以前よりも大きくなっています。通訳は以前よりもずっと堅牢だと思います。 RがCよりも100〜300倍遅いことは間違いありませんが、通常、ボトルネックはC/C++に委任できるコードの数行に集中しています。データ操作と統計分析におけるRの長所を他の言語に委任するのは間違いだと思います。これらの場合、パフォーマンスのペナルティは低く、いずれにしても開発労力を節約する価値があります。実行時間だけが問題であれば、私たちはすべてアセンブラーを作成することになります。

15
gappy

私はパッケージの書き方を理解するつもりでしたが、時間を費やしていません。ミニプロジェクトごとに、低レベル関数をすべて「functions /」というフォルダーに保存し、明示的に作成した別の名前空間にソースします。

次のコード行は、検索パスに「myfuncs」という名前の環境がまだ存在しない場合(attachを使用)、作成し、「functions /」ディレクトリの.rファイルに含まれる関数をその環境に取り込みます(使用sys.source)。通常、これらの行は、高レベル関数(低レベル関数を呼び出す)が呼び出される「ユーザーインターフェイス」用のメインスクリプトの先頭に配置します。

if( length(grep("^myfuncs$",search()))==0 )
  attach("myfuncs",pos=2)
for( f in list.files("functions","\\.r$",full=TRUE) )
  sys.source(f,pos.to.env(grep("^myfuncs$",search())))

変更を加えるときは、常に同じ行でソースを変更するか、次のようなものを使用できます。

evalq(f <- function(x) x * 2, pos.to.env(grep("^myfuncs$",search())))

作成した環境で追加/変更を評価します。

私は知っていますが、それについて形式的になりすぎることは避けます(ただし、機会があれば、パッケージシステムを奨励します-できれば将来的にはそのように移行することを願っています)。

コーディング規約については、これが美学に関して私が見た唯一のことです(私はそれらが好きで、大まかに従いますが、Rでは中括弧をあまり使いません):

http://www1.maths.lth.se/help/R/RCC/

UseRでのさまざまなプレゼンテーション(通常は基調講演)で提案された割り当て演算子としての[、drop = FALSE]および<-の使用に関して、他の「慣習」があります!カンファレンスですが、これらのどれも厳密ではないと思います(ただし、[、drop = FALSE]は、期待する入力がわからないプログラムには便利です)。

11
hatmatrix

パッケージを好むもう一人の人として私を数えてください。マニュアルページやビネットを書く必要があるかどうか(リリースされるまで)はかなり貧弱であることは認めますが、それはソースdoeをバンドルする本当に便利な方法になります。さらに、コードの保守について真剣に考えると、Dirkが提起するポイントはすべてplyaになります。

6
geoffjentry

私も同意します。 package.skeleton()関数を使用して開始します。コードが再び実行されることはないと思う場合でも、後で時間を節約できるより一般的なコードを作成する動機付けに役立つ場合があります。

グローバル環境へのアクセスに関しては、<<-演算子を使用すると簡単ですが、推奨されません。

4
cameron.bracken

パッケージの書き方をまだ学んでいないので、私は常にサブスクリプトを調達することで整理してきました。クラスを書くことに似ていますが、それほど複雑ではありません。プログラム的にエレガントではありませんが、時間の経過とともに分析を積み重ねていきます。動作する大きなセクションを作成したら、ワークスペースオブジェクトを使用するため、それを別のスクリプトに移動して、単にソースにするだけです。おそらく、いくつかのソースからデータをインポートし、それらをすべてソートして、交差点を見つける必要があります。そのセクションを追加のスクリプトに入れることができます。ただし、「アプリケーション」を他の人に配布したい場合、または何らかのインタラクティブな入力を使用する場合は、おそらくパッケージが適切なルートです。研究者として、私は分析コードを配布する必要はほとんどありませんが、頻繁にそれを増強または微調整する必要があります。

3
kpierce8

また、R大規模プロジェクトをまとめるための適切なワークフローの聖杯を探しています。昨年、このパッケージは rsuite と呼ばれていましたが、私が探していたものでした。このRパッケージは、大規模なRプロジェクトの展開用に明示的に開発されましたが、小規模、中規模、大規模なRプロジェクトに使用できることがわかりました。実世界の例へのリンクをすぐに(下記)提供しますが、最初にrsuiteを使用してRプロジェクトを構築する新しいパラダイムを説明します。

注意。私はrsuiteの作成者でも開発者でもありません。

  1. 私たちはRStudioですべて間違ったプロジェクトを行ってきました。目標は、プロジェクトやパッケージの作成ではなく、より大きなスコープの作成であるべきです。 rsuiteでは、スーパープロジェクトまたはマスタープロジェクトを作成します。これは、可能なすべての組み合わせで、標準のRプロジェクトとRパッケージを保持します。

  2. Rスーパープロジェクトを作成することにより、下位のRプロジェクトの下位レベルを管理するためにUnix makeは必要なくなります。上部でRスクリプトを使用します。披露させて。 rsuiteマスタープロジェクトを作成すると、次のフォルダー構造が得られます。

enter image description here

  1. フォルダーRは、プロジェクト管理スクリプトを配置する場所であり、makeを置き換えるものです。

  2. フォルダーpackagesは、rsuiteがスーパープロジェクトを構成するすべてのパッケージを保持するフォルダーです。また、インターネットからアクセスできないパッケージをコピーして貼り付けることもできます。rsuiteも同様にビルドします。

  3. フォルダーdeploymentは、_rsuiteがパッケージDESCRIPTIONファイルで示されたすべてのパッケージバイナリを書き込む場所です。したがって、これにより、完全に再現可能な時間を予測できます。

  4. rsuiteには、すべてのオペレーティングシステム用のクライアントが付属しています。私はそれらをすべてテストしました。ただし、RStudioのaddinとしてインストールすることもできます。

  5. rsuiteでは、独自のフォルダーcondaに分離condaインストールを構築することもできます。これは環境ではなく、マシンのAnacondaから派生した物理Pythonインストールです。これは、RのSystemRequirementsと連携して動作します。Rから、必要なcondaチャネルから、必要なPythonパッケージをすべてインストールできます。

  6. また、オフラインのときにRパッケージをプルするローカルリポジトリを作成したり、すべてをより速くビルドしたりすることもできます。

  7. 必要に応じて、RプロジェクトをZipファイルとしてビルドし、同僚と共有することもできます。同僚に同じRバージョンがインストールされていれば実行されます。

  8. 別のオプションは、Ubuntu、Debian、またはCentOSでプロジェクト全体のコンテナを構築することです。そのため、プロジェクトビルドでZipファイルを共有する代わりに、Dockerコンテナー全体をプロジェクトの実行準備が整った状態で共有します。

rsuiteで多くの実験を行って、完全な再現性を求め、グローバル環境にインストールするパッケージに依存しないようにしています。パッケージの更新をインストールするとすぐに、プロジェクトが動作を停止することが多いため、これは間違っています。特に、特定のパラメーターを持つ関数への非常に具体的な呼び出しを持つパッケージです。

私が最初に実験を始めたのは、bookdownの電子書籍でした。私は、6か月以上の時の試練を乗り切るためのブックダウンができるほど幸運ではありませんでした。だから、私がしたことは、元のブックダウンプロジェクトをrsuiteフレームワークに従うように変換することです。プロジェクトのdeploymentフォルダーに独自のパッケージセットがあるため、グローバルなR環境の更新について心配する必要はありません。

次にしたことは、機械学習プロジェクトを作成することでしたが、rsuiteの方法で作成しました。マスター、最上位のオーケストレーションプロジェクト、およびマスターの制御下にあるすべてのサブプロジェクトとパッケージ。 Rでコーディングする方法が本当に変わり、生産性が向上します。

その後、rTorchという私の新しいパッケージで作業を始めました。これは、主にrsuite;により可能になりました。考えて大きくなることができます。

ただし、アドバイスがあります。 rsuiteの学習は簡単ではありません。 Rプロジェクトを作成する新しい方法を提示するため、苦労します。最初の試みでがっかりしないでください、あなたがそれを作るまで斜面を登り続けてください。オペレーティングシステムとファイルシステムの高度な知識が必要です。

いつの日かRStudioにより、メニューからrsuiteが行うようなオーケストレーションプロジェクトを生成できるようになります。素晴らしいものになるだろう。

リンク:

RSuite GitHUbリポジトリ

r4ds bookdown

ケラと光沢のあるチュートリアル

moderndive-book-rsuite

interpretable_ml-rsuite

IntroMachineLearningWithR-rsuite

clark-intro_ml-rsuite

hyndman-bookdown-rsuite

statistical_rethinking-rsuite

fread-benchmarks-rsuite

dataviz-rsuite

小売セグメンテーション-h2o-チュートリアル

telco-customer-churn-tutorial

sclerotinia_rsuite

1
f0nzie