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

手順

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



私的パッケージ作りの第一歩は標準パッケージ tools 中の関数 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 の起動ディレクトリ(今は /tmp)に /tmp/pkgA というディレクトリが作られた。その中身は次の通り。サブディレクトリ R には関数 f,g の定義ファイル f.R, g.R が、サブディレクトリ data にはデータ d,e の定義ファイル d.rda, e.rda (ただしバイナリファイル)が入っている。それ以外は空サブディレクトリか、形式だけの空ファイル。

hoge@KNX40HDA3:/tmp/pkgA$ ls
DESCRIPTION  R  README  data  man  src

次に以下の内容のファイル /tmp/pkgA/NAMESPACE を置く。これはパッケージをロードしたときに外から見えるようにしたい関数の一覧。

export(f, g)

次にパッケージをインストール(Linux ではルートで実行する必要)。 この命令は普通 CRAN から入手したパッケージファイル foo.tar.gz に対して 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 を起動してインストールした自作パッケージ 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>

次にディレクトリ pkgA のクローン 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

という具合に名前の衝突を避けたければ、一々 pkgA::f, pkgB::f などと使い分ける(やる気になりますか)。

背景

初級Q&Aで「関数を含むファイルを多数作ったら、名前の衝突が起きてこまる、どうしたら良いのでしょうか」という趣旨の質問がありました。一番簡単な方法はファイル A にある関数には A.fun1, A.fun2, ... 等の名前をつけることでしょうが、郷に入れば郷に従えで、R 流のやりかたを使ってみたらどうでしょう。つまり、ファイル毎にパッケージ化して、それを読み込むことです。その際、パッケージに NAMESPACE というファイルを付け加えることがコツです。

パッケージというと、CRAN に登録を目指す強者だけが作れる難しいものという感じがしますが、私的に使うパッケージなら必要最小限の努力で作れます。以下そうしたやりかたを解説します *1。また以下の説明は Linux で行います。Mac や MSW ではどうするのか知りませんが、同様の操作ができるはず。*2


*1 といかにも知ったかぶりで書きますが、私も今回初めて勉強したので、おかしなところがあるかもしれません
*2 取り敢えず関数だけです。データはどうする、などと聞いても答える気はありません。既存パッケージのソースでも良く見て調べてください。

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Google
WWW を検索 OKADAJP.ORG を検索
Last-modified: 2015-03-01 (日) 01:15:59 (1717d)