スキップしてメイン コンテンツに移動

R でいまどきなパッケージ開発 (devtools, testthat, roxygen2)

追記 (2012/04/21): 以下のコードは S4 classes で書いていますが、R5 reference classes で書き直してみました。こちらもどうぞ。http://blog.hackingisbelieving.org/2012/04/r5-reference-class-r-devtools-testthat.html

R のパッケージ開発の情報があまりないので、自分はこんな感じでやってます、というのを書いてみます。パッケージ開発支援の devtools と単体テスト支援の testthat, そしてドキュメント生成支援の roxygen を使うのがいまどきっぽいです。

そもそもパッケージを作製しているひとをあまりみたことがないので、もっとこうすべき、というのがあれば教えてほしいです。

今回はデモケースとして S4 OOP で、Idol クラスを定義し、とある身体的特徴の統計量を計算するパッケージを作ります。R のプロンプトは > で、シェルのプロンプトは $ で示しています。

0. 準備
必要になるパッケージをインストールします。
$ sudo R
> install.packages(devtools)
> install.packages(testthat)
> q()

devtools の設定をします。~/.Rpackages に設定を記述します。
$ emacs ~/.Rpackages
list(
  default = function(x) {
    file.path("~/Project/dev/R/", x, x)
  },
  "idol" = "~/Projects/dev/R/idol/idol"
)

以下の行は今回パッケージを作製する作業ディレクトリになります。
  "idol" = "~/Projects/dev/R/idol/idol"

1. ともあれ実装を始める
作業ディレクトリに移動します。
$mkdir -p ~/Project/dev/R/idol
$ cd ~/Project/dev/R
emacs を起動して以下のようなコードを書いていきます。
$ emacs idol.R
setClass("Idol",
  representation(
    first.name = "character",
    last.name  = "character",
    height     = "numeric",
    weight     = "numeric",
    bust       = "numeric",
    waist      = "numeric",
    hip        = "numeric"
  ),
  prototype(
    first.name = "Hibiki",
    last.name  = "Ganaha",
    height     = 152,
    weight     = 41,
    bust       = 83,
    waist      = 56,
    hip        = 80
  )
)
R を起動し実行してみます。
> source("idol.R")
> my.idol <- new("Idol")
> my.idol
An object of class "Idol"
Slot "first.name":
[1] "Hibiki"

Slot "last.name":
[1] "Ganaha"

Slot "height":
[1] 152

Slot "weight":
[1] 41

Slot "bust":
[1] 83

Slot "waist":
[1] 56

Slot "hip":
[1] 80

2. devtools の環境に移行する
次に devtools を使ってパッケージの開発をする準備をします。package に必要なファイルやディレクトリを作製します。
> package.skeleton("idol", code_file="idol.R")
Creating directories ...
Creating DESCRIPTION ...
Creating Read-and-delete-me ...
Copying code files ...
Making help files ...
Done.
Further steps are described in './idol/Read-and-delete-me'.

devtools を読み込み、コードを読み込みます。
library("devtools")
load_all("idol")
Loading idol

以下のように idol ディレクトリとそのなかにいくつかのファイルができているはずです。
$ tree .  
.
├── idol
│   ├── DESCRIPTION
│   ├── R
│   │   └── idol.R
│   ├── Read-and-delete-me
│   ├── inst
│   │   └── tests
│   └── man
│       ├── Idol-class.Rd
│       └── idol-package.Rd
└── idol.R

5 directories, 6 files

Read-and-delete-me はいらないので消します。
$ rm Read-and-delete-me 

3. メソッドのテストを書く
テストコードを入れるディレクトリを作ります。(devtools ではこの場所にあることを推奨しているけど、idol/test ではないのかな?)
$ mkdir -p idol/inst/tests/

テストを書きます。身体的特徴を示す統計量を計算するメソッドをつくるので、そのテストを書きます。
$ emacs idol/inst/tests/test-idol.R
test_that("check effective cap ratio", {
  height <- 152
  bust   <- 83
  waist  <- 56
  my.ecr <- (bust - waist) * 100 / height

  my.idol <- new("Idol")
  expect_equal(
    my.ecr,
    effective.capsize(my.idol)
  )
}
)
test_that("check substantial aspect ratio", {
  height <- 152
  bust   <- 83
  waist  <- 56
  hip    <- 80
  my.sar <- (bust + waist + hip) * 10 / height

  my.idol <- new("Idol")
  expect_equal(
    my.sar,
    substantial.aspect(my.idol)
  )
}
)

devtools の test() を使ってテストします。当然失敗します。load_all() しなおす必要はないようです。
> test()

4. メソッドの定義
2つのメソッドを定義します。
$ emacs idol.R
setGeneric("effective.capsize", function(object) { standardGeneric("effective.capsize") })
setMethod("effective.capsize", "Idol",
  function(object) { (object@bust - object@waist) * 100 / object@height }
)

setGeneric("substantial.aspect", function(object) { standardGeneric("substantial.aspect") })
setMethod("substantial.aspect", "Idol",
  function(object) { (object@bust + object@waist + object@hip) * 10 / object@height }
)
テストします。今度は通るはずです。
> test()
Loading idol
Testing idol
..

実装しているときに、少し挑戦的なコードを書きたいときは、dev_mode() を使います。Ruby on Rails の production, development mode のようなものですね。

> dev_mode()

します。もう一度、dev_mode() をすると元の環境に戻ります。dev_mode() が ON のときは、.libPaths にあるディレクトリに、development mode のコードツリーが生成されます。

5. データファイルを作成する
データを作ります。idol/data に Rのデータファイルを置きます。
$ mkdir idol/data
> hibiki <- new("Idol")
> azusa <- new("Idol", first.name="Azusa", last.name="Miura", height=168, weight=48, bust=91, waist=59, hip=86)
> chihaya <- new("Idol", first.name="Chihaya", last.name="Kisaragi", height=162, weight=41, bust=72, waist=55, hip=78)
> save(hibiki, chihaya, azusa, file="idol/data/idolmaster765.rda")

$ emacs idol/data/datalist
idolmaster765

6. コメントへドキュメントを書く
roxygen 形式でコードのなかにコメントとしてドキュメントを埋め込みます。

まず method に対してドキュメントを書きます。example もちゃんと埋めなければなりません。
$ emacs idol/R/idol.R
#' Calcuate effective bust cap size ratio
#'
#' This function calcuate effective bust cap size ratio of your idol
#' when you can know her cap size.
#'
#' @param object idol object
#' @keywords bust
#' @export
#' @examples
#' my.idol     <- new("Idol")
#' my.idol.ecr <- effective.capsize(my.idol)
setGeneric("effective.capsize", function(object) { standardGeneric("effective.capsize") })
setMethod("effective.capsize", "Idol",
  function(object) { (object@bust - object@waist) * 100 / object@height }
)
#' Calcuate substantial aspect ratio
#'
#' This function calcuate substantial aspect ratio of your idol
#' This statistic represents her body shape.
#'
#' @param object idol object
#' @keywords body shape
#' @export
#' @examples
#' my.idol     <- new("Idol")
#' my.idol.sbr <- substantial.aspect(my.idol)
setGeneric("substantial.aspect", function(object) { standardGeneric("substantial.aspect") })
setMethod("substantial.aspect", "Idol",
  function(object) { (object@bust + object@waist + object@hip) * 10 / object@height }
)

次に、package とデータセットについてドキュメントを書きます。ソースコードがないので、NULL を入れるのがポイントです。
$ emacs idol/R/idol.R

#' idol
#'
#' @name idol
#' @docType package
#' @aliases idol package-idol
#' @import methods
NULL

#' Idols in 765 Production
#'
#' A dataset containing idols with her official profile.
#' A data has three typical idols in 765 Production (Hibiki,
#' Azusa and Chihaya).
#' The variables are as follows:
#'
#' \itemize{
#'   \item first.name. Her first name
#'   \item last.name. Her last name
#'   \item height. Her body height in cm
#'   \item weight. Her body weight in kg
#'   \item bust. Her top bust size in cm
#'   \item waist. Her waist size in cm
#'   \item hip. Her hip size in cm
#' }
#'
#' @docType data
#' @keywords datasets
#' @name idolmaster765
#' @usage data(idolmaster765)
#' @format A data object with three idol objects
#' @references \url{http://www.bandainamcogames.co.jp/cs/list/idolmaster/}
NULL


ドキュメントを生成します。
> document("idol")

idol/man/ 以下に, effective.capsize.Rd ,substantial.aspect.Rd, idol.RD, idolmaster765.Rd が出力されています。また NAMESPACE が出力されています(これは便利)。

この3-5のステップを繰り返してコーディングを続けます。

7. パッケージングする
まず、DESCRIPTION を書きます。
$ emacs idol/DESCRIPTION
Package: idol
Type: Package
Title: Make your idol
Version: 1.0
Date: 2012-01-20
Author: Itoshi NIKAIDO
Maintainer: Itoshi NIKAIDO <dritoshi@gmail.com>
Description: Make your virtual idol in R. You can indicate your favorite body
    shape to your idol. This package provide idol class and some method for
    calculating some statistic of her body shape.
License: Artistic-2.0
LazyLoad: yes
Depends:
    methods
Collate:
    'idol.R'

R CMD check のときに単体テストが走るように設定します。
$ emacs idol/inst/tests/run-all.R
library(testthat)
library(idol)

test_package("idol") 

そしてパッケージのチェックをします。いわゆる R CMD check です。
> check()
次に パッケージの tar.gz を作成します。いわゆる R CMD build です。
> build()
~/Projects/dev/R/idol/idol_1.0.tar.gz ができています。
最後にこれをインストールしてみましょう。いわゆる R CMD INSTALL です。
> install()

8. パッケージを使ってみる
$ R
> library("idol")
hibiki <- new("Idol")
> effective.capsize(hibiki)
[1] 17.76316
> substantial.aspect(hibiki)
[1] 14.40789
> data(idolmaster765)
> ls()
[1] "azusa"   "chihaya" "hibiki"
> sapply(c(azusa, chihaya, hibiki), effective.capsize)
[1] 19.04762 10.49383 17.76316
> sapply(c(azusa, chihaya, hibiki), substantial.aspect)
[1] 14.04762 12.65432 14.40789

課題
というかよくわからないところ。

  1. package.skeleton() が出力した Idol-class.Rd, idol-package.Rd を roxygen で書くには? 2つのドキュメントを消してしまい、どこかのファイルにドキュメントを埋めこみ、コードの部分を NULL にするテクニックがあるようです。教えてくれたさんに感謝! 困ったら hadley  さんのコード読めばよさげ。 https://github.com/hadley/ggplot2/blob/master/R/ggplot2.r
  2. data のドキュメントを roxygen で書くには? こちらも上と同じように解決できる。
  3. devtools で data をうまくロードできない?
  4. Vignettes, NEWS, CITATION まわりを調査

kohske
@dritoshi 1、2個目についてはNULLに対してroxygenなドキュメント書いてるケースを見ますね。 https://t.co/L0Yzry5q みたいな感じです。
12/01/20 22:05


参考ウェブサイト
有効巨乳率と実質縦横比:
http://www.asahi-net.or.jp/~bh3h-smjy/zundo/kensho.htm

我那覇響(ポニーテール)
http://765pro.jp/idol/hibiki.html

以上、コードは github においておきました。

それでは、みなさま、なんくるないさー(挨拶


コメント

このブログの人気の投稿

シーケンスアダプタ配列除去ツールまとめ

FASTQ/A file からシーケンスアダプター配列やプライマー配列を除くためのプログラムをまとめてみる。 まず、配列の除去には大別して2つの方向性がある。ひとつは、アダプター配列を含む「リード」を除いてしまう方法。もうひとつは除きたい配列をリードからトリムする方法である。後者のほうが有効リードが増えるメリットが、綺麗に除ききれない場合は、ゲノムへのマップ率が下がる。 気をつける点としては、アダプター/プライマーの reverse complement を検索するかどうか。paired end の際には大事になる。クオリティでトリムできるものや、Paired-end を考慮するものなどもある。アダプター/プライマー配列の文字列を引数として直接入力するものと、multi fasta 形式で指定できるももある。 From Evernote: シーケンスアダプタ配列除去ツールまとめ TagDust http://genome.gsc.riken.jp/osc/english/software/src/nexalign-1.3.5.tgz http://bioinformatics.oxfordjournals.org/content/25/21/2839.full インストール: curl -O http://genome.gsc.riken.jp/osc/english/software/src/tagdust.tgztar zxvf tagdust.tgz cd tagdust/ make sudo make install rehash 使いかた: tagdust adapter.fasta input.fastq -fdr 0.05 -o output.clean.fastq -a output.artifactual.fastq 解説: 入出力形式は fastq/a が使える。リード全体を除く。速い。アダプター配列を fasta 形式で入力できるのが地味に便利で、これに対応しているものがなかなかない。Muth–Manber algorithm (Approximate multiple

ChIP-seq の Peak calling tool を集めたよ

ほかにもあったら教えてください。プログラム/プロジェクト名がツールのプロジェクトサイトへのリンク。その論文タイトルは論文へのリンクになっています。 ツール名の50音順です。 CCCT -  A signal–noise model for significance analysis of ChIP-seq with negative control , chipdiff と同じグループ CisGenome -  CisGenome: An integrated software system for analyzing ChIP-chip and ChIP-seq data . ChromSig -  ChromaSig: a probabilistic approach to finding common chromatin signatures in the human genome. ChIPDiff -  An HMM approach to genome-wide identification of differential histone modification sites from ChIP-seq data ChIP-Seq Analysis Server FindPeaks -  FindPeaks 3.1: a tool for identifying areas of enrichment from massively parallel short-read sequencing technology. Version 4.0 is out. GLITR -  Extracting transcription factor targets from ChIP-Seq data HPeak -  HPeak: an HMM-based algorithm for defining read-enriched regions in ChIP-Seq data MACS -  Model-based Analysis of ChIP-Seq (MACS). PeakSeq -  PeakSeq enables systematic scoring of ChIP-seq experimen

大学の研究室でアカデミックプランが使えるICTツール

自分らでサーバ管理したくないので、SaaS系とローカルで動くソフトのみ。ローカルで動くソフトに関しては、Mac or Docker で動くもののみ。 無償 G Suite for Education  (ドキュメント共有、カレンダーなど) GitHub Education  (ソースコード管理) esa.io アカデミックプラン  (知識共有) Tableau  (データ可視化) Scrapbox  (知識共有) GROWI.cloud  (Wikiなど) 割引 Slack の教育支援プログラム  (ビジネスチャット) Dropbox Education  (ファイル共有、ドキュメント共有) Office 356  (オフィスソフト) Adobe Creative Cloud  (画像編集) AutoDesk for Education  (CADなど) これから申し込んでいくところなので、本当に使えるかはわかりせん。使えた使えないなどの情報やほかのツールでお勧めがあれば教えてもらえると嬉しいです。 アカデミアでなくても無料で使えるツールのうち、うちで使うであろうものは以下に列挙していく。 Google Colaboratory  (データ解析) Overleaf  (論文執筆) Rstudio  (開発, データ解析) VS code (開発)