// 間瀬茂 2006.02.22 

R オブジェクトが多数ある場合に名前の衝突が起きる。この問題を回避するために、パッケージを作成して名前空間を分離する方法を記す。ポイントはパッケージ作成にあたって ''NAMESPACE'' というファイルを用いることである。

* 手順
- 必要な関数 my.func() を定義
- package.skelton() でパッケージの雛形を作成
- NAMESPACE ファイルに利用する関数を記述
- パッケージ作成
- パッケージをインストールして利用

* 背景
初級Q&Aで「関数を含むファイルを多数作ったら、名前の衝突が起きてこまる、どうしたら良いのでしょうか」という趣旨の質問がありました。一番簡単な方法はファイル COLOR(red){A} にある関数には COLOR(red){A.fun1}, COLOR(red){A.fun2}, ... 等の名前をつけることでしょうが、COLOR(blue){郷に入れば郷に従え}で、R 流のやりかたを使ってみたらどうでしょう。つまり、ファイル毎にパッケージ化して、それを読み込むことです。その際、パッケージに COLOR(red){NAMESPACE} というファイルを付け加えることがコツです。~
~
パッケージというと、CRAN に登録を目指す強者だけが作れる難しいものという感じがしますが、私的に使うパッケージなら必要最小限の努力で作れます。以下そうしたやりかたを解説します ((といかにも知ったかぶりで書きますが、私も今回初めて勉強したので、おかしなところがあるかもしれません))。また以下の説明は Linux で行います。Mac や MSW ではどうするのか知りませんが、同様の操作ができるはず。((取り敢えず関数だけです。データはどうする、などと聞いても答える気はありません。既存パッケージのソースでも良く見て調べてください。))
~
~
私的パッケージ作りの第一歩は標準パッケージ COLOR(red){tools} 中の関数 COLOR(red){package.skeleton} を使うことです。~
 > library(tools)    # tools パッケージは既定ではロードされない
 > ?package.skeleton # 関数説明をまず読む(が、何やら難しいことが一杯書いてある)
 
 # 次のような関数とデータを作成(もしくは定義ファイルから読み込む)
 
 > f <- function(x,y) x+y
 > g <- function(x,y) x-y
 > d <- data.frame(a=1, b=2)
 > e <- rnorm(1000)
 > ls()
 [1] "d" "e" "f" "g" "last.warning"
 
 # 現在のセッション中のオブジェクトからパッケージ pkgA を作る 
 
 > package.skeleton(list=c("f","g","d","e"), name="pkgA")
 Creating directories ...
 Creating DESCRIPTION ...
 Creating READMEs ...
 Saving functions and data ...
 Making help files ...
 Created file named './pkgA/man/pkgA.package.Rd'.
 Edit the file and move it to the appropriate directory.
 Created file named './pkgA/man/f.Rd'.
 Edit the file and move it to the appropriate directory.
 Created file named './pkgA/man/g.Rd'.
 Edit the file and move it to the appropriate directory.
 Created file named './pkgA/man/d.Rd'.
 Edit the file and move it to the appropriate directory.
 Created file named './pkgA/man/e.Rd'.
 Edit the file and move it to the appropriate directory.
 Done.
 Further steps are described in ./pkgA/README
これで R の起動ディレクトリ(今は COLOR(red){/tmp})に COLOR(red){/tmp/pkgA} というディレクトリが作られた。その中身は次の通り。サブディレクトリ COLOR(red){R} には関数 f,g の定義ファイル COLOR(red){f.R}, COLOR(red){g.R} が、サブディレクトリ COLOR(red){data} にはデータ d,e の定義ファイル COLOR(red){d.rda}, COLOR(red){e.rda} (ただしバイナリファイル)が入っている。それ以外は空サブディレクトリか、形式だけの空ファイル。
 hoge@KNX40HDA3:/tmp/pkgA$ ls
 DESCRIPTION  R  README  data  man  src
次に以下の内容のファイル COLOR(red){/tmp/pkgA/NAMESPACE} を置く。これはパッケージをロードしたときに外から見えるようにしたい関数の一覧。 
 export(f, g)
次にパッケージをインストール(Linux ではルートで実行する必要)。 この命令は普通 CRAN から入手したパッケージファイル COLOR(red){foo.tar.gz} に対して COLOR(red){R CMD INSTALL foo.tar.gz} として実行するが、この命令は実際はファイルを解凍展開したディレクトリを作成し、そのディレクトリを操作するから、最初から展開された結果かのようなディレクトリに対しても使える。
 root@KNX40HDA3:/tmp# R CMD INSTALL pkgA
 * Installing *source* package 'pkgA' ...
 ** libs
 WARNING: no source files found
 chmod: cannot access `/usr/local/lib/R/site-library/pkgA/libs/*': そのようなファイルやディレクトリはありません
 ** R
 ** data
 ** help
  >>> Building/Updating help pages for package 'pkgA'
      Formats: text html latex example
   d                                 text    html    latex   example
   e                                 text    html    latex   example
   f                                 text    html    latex   example
   g                                 text    html    latex   example
   pkgA.package                      text    html    latex   example
 ** building package indices ...
 * DONE (pkgA)
次に R を起動してインストールした自作パッケージ COLOR(red){pkgA} をロードします。
 > library(pkgA)
 > ls()      # 表向き何も無い(つまり大局的環境  .globalEnv には何も無い)
 character(0)
 > f       # しかし、NAMESPACE ファイルで export 指示した関数は存在する
 function (x, y)
 x + y
 <environment: namespace:pkgA>
 > g
 function (x, y)
 x - y
 <environment: namespace:pkgA>
次にディレクトリ COLOR(red){pkgA} のクローン COLOR(red){pkgB} をわざと作る(当然中身はまったく同じ)。そして上と同じ操作でライブラリ化する。
 > library(pkgB) # 新しい pkgB を読み込む
 
 次のパッケージを付け加えます: 'pkgB'
 
        The following object(s) are masked from package:pkgA :
 
         f g           # パッケージ pkgB の f,g がパッケージ pkgA のそれを隠す
 
 > ls()
 character(0)
 > f        # この f は直近に読み込んだパッケージ pkgB のそれ
 function (x, y)
 x + y
 <environment: namespace:pkgB>
 > g        # この g は直近に読み込んだパッケージ pkgB のそれ
 function (x, y)
 x - y
 <environment: namespace:pkgB>
 > pkgA::f          # (追い出された)パッケージ pkgA の関数 f
 function (x, y)
 x + y
 <environment: namespace:pkgA>
 > pkgA::f(1,2)     # (追い出された)パッケージ pkgA の関数 f を使用する
 [1] 3
 > pkgB::f          #  パッケージ pkgB の関数 f として参照
 function (x, y)
 x + y
 <environment: namespace:pkgB>
 > pkgB::f(1,2)  # パッケージ pkgB の関数 f を使用する(今は単に f(1,2) としたのと同じ!)
 [1] 3
という具合に名前の衝突を避けたければ、一々 COLOR(red){pkgA::f}, COLOR(red){pkgB::f} などと使い分ける(やる気になりますか)。

* 背景
初級Q&Aで「関数を含むファイルを多数作ったら、名前の衝突が起きてこまる、どうしたら良いのでしょうか」という趣旨の質問がありました。一番簡単な方法はファイル COLOR(red){A} にある関数には COLOR(red){A.fun1}, COLOR(red){A.fun2}, ... 等の名前をつけることでしょうが、COLOR(blue){郷に入れば郷に従え}で、R 流のやりかたを使ってみたらどうでしょう。つまり、ファイル毎にパッケージ化して、それを読み込むことです。その際、パッケージに COLOR(red){NAMESPACE} というファイルを付け加えることがコツです。~
~
パッケージというと、CRAN に登録を目指す強者だけが作れる難しいものという感じがしますが、私的に使うパッケージなら必要最小限の努力で作れます。以下そうしたやりかたを解説します ((といかにも知ったかぶりで書きますが、私も今回初めて勉強したので、おかしなところがあるかもしれません))。また以下の説明は Linux で行います。Mac や MSW ではどうするのか知りませんが、同様の操作ができるはず。((取り敢えず関数だけです。データはどうする、などと聞いても答える気はありません。既存パッケージのソースでも良く見て調べてください。))


トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS