Share
Embed
CRANへの道
ベイズ統計学勉強回春'24で発表した資料です。
私が開発したexametrikaパッケージをCRANに登録した時のノウハウについて解説してます。
Koji E. Kosugi
February 23, 2025
Transcript
63 slides
-
手順4. プロジェクトを 作ろう 1. バージョンコントロールを選ぶ 2. Gitを選ぶ 3. レポジトリ名はさっきのURL を。場所はもちろん自由に選ん
で 4. Create! The way to CRAN 8 -
devtools::create(".") ! New project "BJ2025" is nested inside an existing
project ./, which is rarely a good idea. If this is unexpected, the here package has a function, here::dr_here() that reveals why ./ is regarded as a project. Do you want to create anyway? 1: Absolutely 2: Absolutely not 3: Nope Selection: 1 The way to CRAN 11 -
Setting active project to "/Users/napier3/XXXXXXXXXXXXXXXXXXXXXXX/BJ2025". Creating R/. Writing DESCRIPTION. Package:
BJ2025 Title: What the Package Does (One Line, Title Case) Version: 0.0.0.9000 Authors@R (parsed): * First Last [email protected] [aut, cre] (YOUR-ORCID-ID) Description: What the package does (one paragraph). License: use_mit_license() , use_gpl3_license() or friends to pick a license Encoding: UTF-8 Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.2 The way to CRAN 12 -
Writing NAMESPACE. ! Overwrite pre-existing file BJ2025.Rproj? 1: No 2:
Definitely 3: Nope Selection: 2 Writing BJ2025.Rproj. Adding "^BJ2025\.Rproj " to .Rbuildignore. ✔ Adding ".Rproj.user" to .gitignore. ✔ Adding "^\\.Rproj\\.user " to .Rbuildignore. Setting active project to "<no active project>". The way to CRAN 13 -
フォルダ構成はこうせい exametrikaパッケージの構成はこんな感じでした PackageFolder ┣ data ┣ .Rbuildignore ┣ develop ┣
.Rhistory ┣ docs ┣ .gitignore ┣ inst ┣ DESCRIPTION ┣ man ┣ Package.Rproj ┣ R ┣ LICENSE ┣ tests ┣ NAMESPACE ┣ tools ┗ README.md The way to CRAN 14 -
主要なフォルダの説明(2) data/ パッケージに同梱するデータセット .rda形式で保存された内部データ inst/ パッケージのその他のファイル スペルチェック(後述)の際につかうWORDLISTを入れてます docs/ パッケージのドキュメント Github
Pagesで表示させるHTMLをここに入れるようにする The way to CRAN 16 -
DESCRIPTIONのサンプル Package: exametrika Type: Package Title: Test Theory Analysis and
Biclustering Version: 1.2.0 Authors@R: person("Koji Kosugi",role=c("aut","cre"), email="[email protected]", comment = c(ORCID = "0000-0001-5816-0099")) Description: # 生成AIに英語でいろいろ書いてもらいましょう! License: MIT + file LICENSE Language: en-US Encoding: UTF-8 LazyData: true BuildVignettes: true URL: https://kosugitti.github.io/exametrika/ Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.2 Suggests: testthat (>= 3.0.0) Config/testthat/edition: 3 Depends: R (>= 4.1.0), mvtnorm, igraph The way to CRAN 19 -
DESCRIPTIONを書く時の注意 依存関係(自分のパッケージが使うパッケージ)を全部書く。 Rのバージョンにも注意( |> はR>=4.1) Roxygen のバージョンもローカルのバージョンとあってるように。 著者情報の書き方は,名前,役割(下記参照),メアドなど。 "aut" (author)
: パッケージの主要な作者 "cre" (creator) : パッケージのメンテナ(連絡担当者) "ctb" (contributor) : コードやドキュメントの貢献者 "cph" (copyright holder) : 著作権保持者 c() を使って複数の著者をかくこともできます。 The way to CRAN 20 -
Roxygenで書こう ヘルプファイルやNAME SPACEを自動でまとめてくれるから,パッケージづくりは楽 になった! #' で始める基本構造 #' @title 関数のタイトル #'
@description 関数の説明 #' @param x 引数の説明 #' @return 返り値の説明 #' @export #' my_function <- function(x) { # 関数の中身 } The way to CRAN 23 -
Roxygen 主要タグ #' @param name 引数の説明。関数で使われている引数が全て含まれていないと, エラーになる #' @return 返り値の説明。
#' @examples 使用例を記述。後述するが,CRANに登録する際はこれを結構書く ように勧められる。 #' @export これがないと関数はパッケージ内からしか参照できず,ユーザは使え ない #' @keywords internal 逆にユーザに触らせないのであればinternalに指定 The way to CRAN 24 -
Roxygen 主要タグ2 #' @importFrom stats mean var 他パッケージから関数をインポートしてくるときは,パッケージ名と関数を列挙。不 足があればエラーになります。 #'
@details 詳細な説明 #' @seealso ここも見てね,みたいなのがあれば便利 #' @references 出典があれば書いておこう The way to CRAN 25 -
Roxygenサンプル #' @title Model Fit Functions for Items #' @description
#' A general function that returns the model fit indices. #' @param U U is either a data class of exametrika, or raw data. When raw data is given, #' it is converted to the exametrika class with the [dataFormat] function. #' @param Z Z is a missing indicator matrix of the type matrix or data.frame #' @param ell_A log likelihood of this model #' @param nparam number of parameters for this model #' @return #' \describe{ #' \item{model_log_like}{log likelihood of analysis model} #' \item{bench_log_like}{log likelihood of benchmark model} #' \item{null_log_like}{log likelihood of null model} #' \item{model_Chi_sq}{Chi-Square statistics for analysis model} #' \item{null_Chi_sq}{Chi-Square statistics for null model} #' \item{model_df}{degrees of freedom of analysis model} #' \item{null_df}{degrees of freedom of null model} #' \item{NFI}{Normed Fit Index. Lager values closer to 1.0 indicate a better fit.} #' \item{RFI}{Relative Fit Index. Lager values closer to 1.0 indicate a better fit.} #' \item{IFI}{Incremental Fit Index. Lager values closer to 1.0 indicate a better fit.} #' \item{TLI}{Tucker-Lewis Index. Lager values closer to 1.0 indicate a better fit.} #' \item{CFI}{Comparative Fit Index. Lager values closer to 1.0 indicate a better fit.} #' \item{RMSEA}{Root Mean Square Error of Approximation. Smaller values closer to 0.0 indicate a better fit.} #' \item{AIC}{Akaike Information Criterion. A lower value indicates a better fit.} #' \item{CAIC}{Consistent AIC.A lower value indicates a better fit.} #' \item{BIC}{Bayesian Information Criterion. A lower value indicates a better fit.} #' } #' @export ItemFit <- function(U, Z, ell_A, nparam) { The way to CRAN 26 -
Roxygen Tips 関数を丸ごと生成AIに渡して, 「Roxygenタグをつけてくれ」とか「descriptionを書い てくれ」といったら,結構やってくれます。チェックは必要だけど,かなり楽。 #' Analyze Student Test Scores
with Multiple Metrics #' #' @title Comprehensive Student Test Analysis #' @description #' This function performs a comprehensive analysis of student test responses, #' calculating various educational measurement metrics including number right scores, #' passage rates, standard scores, percentiles, and stanine scores. #' #' @param U Matrix or data frame of item responses (students x items) #' @param na Value to be treated as missing (default = NULL) #' @param Z Optional matrix of auxiliary information (default = NULL) #' @param w Optional vector of item weights (default = NULL) #' #' @return A data frame containing the following columns: #' \itemize{ #' \item ID - Student identifiers #' \item NR - Number of items responded (excluding NA) #' \item NRS - Number right score #' \item PR - Passage rate #' \item SS - Standard score #' \item Percentile - Percentile rank #' \item Stanine - Stanine score (1-9 scale) #' } #' #' @details #' The function processes raw item responses and calculates multiple educational #' measurement metrics. It handles missing values and can incorporate item weights #' and auxiliary information if provided. #' #' @examples #' \dontrun{ #' # Basic usage with response matrix #' results <- StudentAnalysis(U = response_matrix) #' #' # With missing value specification #' results <- StudentAnalysis(U = response_matrix, na = 9) The way to CRAN 28 -
パッケージ開発の裏話 自分以外の人のためにコードを書いたことがある人あるある ユーザは何をしてくるかわからない コードを書くのと同時にヘルプを書かないと,あとでマニュアルを作るのは大 変。roxygenで同時に書くのは,実は未来の自分のためでもある ヘルプを書いてもユーザが読むとは限らない パッケージはパッケージで独立・完結している必要がある。グローバル変数は当て にできないので,全て引数で受け取り, return
で返す。 受け取るデータの型,サイズ,オプションなどを,関数の冒頭で必ずチェックする 自分でクラスを作るのもいい The way to CRAN 29 -
exametrikaの一般的フロー 関数の冒頭は大体これで始まる。 IRT <- function(U, model = 2, na =
NULL, Z = NULL, w = NULL, verbose = TRUE) { # data format if (!inherits(U, "exametrika")) { tmp <- dataFormat(data = U, na = na, Z = Z, w = w) } else { tmp <- U } ... 入力されたオブジェクト U のクラスを inherits 関数でチェックしてます。 The way to CRAN 32 -
exametrikaの一般的フロー dataFormt 関数は matrix や data.frame など,渡されたものを整形して,いろいろ 変数をセットにして( ret.list ),最後にクラス属性
exametrika と exametrikaData を付与してリターンする。 # Return with appropriate class structure ret <- structure(ret.list, class = c("exametrika", "exametrikaData")) return(ret) ver`1.0から1.1に上げる際に,多値データにも対応させようということになって, ここを書き換える羽目になったから大変だった!設計方針はなるべくしっかり定めま しょうw The way to CRAN 33 -
Rにおける継承の基本 クラスの重要な利点のひとつが「継承」 例: print や plot 関数を継承して独自の出力が可能 基本関数に .package名 を付けることで専用の処理を定義
plot.exametrika <- function(x, type = c( "IIC", "ICC", "TIC", "IRP", "TRP", "LCD", "CMP", "FRP", "RMP", "LRD", "Array", "FieldPIRP", "LDPSR" ), items = NULL, students = NULL, nc = 1, nr = 1, ...) { value <- if (length(class(x)) > 1) tail(class(x), 1) else "None" The way to CRAN 34 -
exametrikaでの継承例1 print.exametrika関数の仕組み 2つ目の属性にモデル名を持たせる 属性に応じて適切な出力形式を選択 各分析手法に特化した結果を表示 注意点 print.exametrika を定義すると通常の print は使用不可
クラスが正しく指定されていないと何も出 力されなくて焦る(った)よ The way to CRAN 35 -
exametrikaでの継承例2 同じ関数名だけどアルゴリズムが違う場合 例えば LRA 関数は,データがbinary, ordinarly, nominalでアルゴリズムが違う ジェネリック関数を使う Rのジェネリック関数(S3メソッド)は、オブジェクトの種類(クラス)に応じて 異なる処理を実行できる仕組み。
LRA に対して, UseMethod を与えることで分岐を可能にする。 引数 ... はこの後ろにくるやつを全部引き継ぐよ!の意味 #' @export LRA <- function(U, ...) { UseMethod("LRA") } The way to CRAN 36 -
まずはデフォルトで通す関数を作る #' @export LRA.default <- function(U, ...) { if (inherits(U,
"exametrika")) { if (U$response.type == "binary") { return(LRA.binary(U, ...)) } else if (U$response.type %in% c("rated", "ordinal")) { return(LRA.ordinal(U, ...)) } else { return(LRA.nominal(U, ...)) } } U <- dataFormat(U, na = na, Z = Z, w = w) LRA(U) } The way to CRAN 37 -
あとは分岐先の関数を作る #' @export LRA.binary <- function(U, nrank = 2, method
= "GTM", mic = FALSE, maxiter = 100, BIC.check = FALSE, seed = NULL) { バイナリの時の処理... } LRA.ordinal <- function(U, nrank = 2, mic = FALSE, maxiter = 100) { 順序の時の処理... } The way to CRAN 38 -
手順8. リリースの準備 パッケージができたらリリースしよう! その前に,いろいろ整えないとね。 devtoolsでチェックしよう。 0 errors | 0
warnings | 0 notes になるまでデバッグだ! The way to CRAN 39 -
手順9. testthatを活用する exametrika は元がMathematicaで提供されているので,結果が合うかどうか検証 する必要があった。 自分のパッケージでも,サンプルデータでちゃんと動くかとか,パラメタリカバ リができるか等,決まりきったテストルーチンがあったほうがいい。 コードの根幹に手を入れると,思わぬところでエラーが出たりするから,テ ストルーチンがあると未然にチェックできる。
コンソールで usethis::use_testthat() とすると,フォルダやDESCRIPTIONを整え てくれる The way to CRAN 40 -
手順9. testthatを活用する usethis::use_testthat() Setting active project to "/Users/XXXXXXXXXXXXXxx/BJ2025". Increasing testthat
version to ">= 3.0.0" in DESCRIPTION. Adding "3" to Config/testthat/edition. Creating tests/testthat/. Writing tests/testthat.R. ☐ Call usethis::use_test() to initialize a basic test file and open it for editing. The way to CRAN 41 -
テストの書き方 テストファイルは独立環境なので,ライブラリの読み込みなどが必要(現実行環境 と同じではない) test_that() で検証したいテストをくくる 最初にテスト名を "テスト名" として入力。出力時にどの関数・どの数字をテスト してるか確認するため {}
内にRコードを。これは特殊な書き方はしない 期待値との照合は expect_equal() や expect_identical() を使う。後者の方が 厳密な一致で,前者は許容誤差( tolerance )を設定可能 機能ごとに別のファイルにしておこう。 The way to CRAN 42 -
手順9. testthatを活用する exametrikaでのテストの例 library(tidyverse) test <- read_excel("../../develop/XXXXXXX.xlsx", sheet = "Test")
Bic <- Biclustering(J35S515, ncls = 6, nfld = 5, method = "B", mic = T) test_that("LRA Test Info", { expect <- test[15:30, 2] %>% as.numeric() expect <- expect[c(5, 1, 2, 6, 3, 7, 4, 8:16)] result <- Bic$TestFitIndices %>% as.numeric() expect_equal(result, expect, tolerance = 1e-4) }) 本家Mathematica の最適化関数の方が精度が高いと信じて, exametrika では最大 1e-4 までの誤差は許容している。 The way to CRAN 43 -
手順10. githubサイトも整えよう Github Pagesの作り方について・・・は省略! レポジトリの Settings から Pages にいって色々設定しよう Mainブランチの
docs フォルダを参照元にしたり,Jekyll themeなんかを使うと綺 麗にできます The way to CRAN 45 -
手順11. またせたな,CRAN じゃあそろそろCRANにも載せてもらいましょう。 library 関数で自分のパッケージ が出てくるなんて胸熱! もう一度いろいろチェックしよう styler::style_pkg() でコード整形 devtools::check()
でローカルチェック devtools::spell_check() でスペルチェック 生成されるドキュメントの中に,ミススペルがないかチェックする 専門用語・略語もエラーとして出てくるので, inst/WORDLIST に回避する用 語を書き込んでおこう The way to CRAN 49 -
WORDLISTの例(プレーンテキストで列記するだけ) 130語ほど登録しました ACM emclus LDparam Rdata Thorndike BMN examinee Mathematica
selectable Tsur BNM examinees monotonicity SIGMOD Ullman BINET exploratively Multigroup softmax Yamanaka CCRR FieldAnalysis Normed stanine Yoshihiro CMP FRP LDLRA StudentAnalysis doi CRP FRM LDPSR testthat Cronbach The way to CRAN 50 -
rhubでオンラインチェック rhub はGithubの仮想環境の中で作動し(Github Actions),様々な環境を作ってパッケ ージが動作するかをチェックしてくれるためのもの。 まず rhub::rhub_setup() で,Github Actionsを動かすコードを生成。Githubとの連携が取れていたら, rhub_check()
を実行。 選択が面倒なら,次の様にコードで書いてもいい。 rhub::rhub_check(platforms = c("linux", "macos", "macos-arm64", "windows"))` ここでは,linuxと,macos, M1-Mac, windowsの環境で実行しているよ。 The way to CRAN 51 -
手順12. いよいよCRANへ CRANに送ってみるよ いよいよCRANにリリースです。 CRANにお手紙を書きます。 usethis::use_cran_comments(open = rlang::is_interactive()) を実行すると,自動的にファイルを用意してくれま す。
usethis::use_cran_comments(open = rlang::is_interactive()) Writing cran-comments.md. Adding "^cran-comments\.md$" to .Rbuildignore. ☐ Modify cran-comments.md. The way to CRAN 57 -
手順12. いよいよCRANへ devtools::release() で投稿〜! まず Confirmation Linkが送られてくる。 「投稿したよな?確認のためにサイトに来 てチェックして」と言われる。 いくつかの了承事項をチェックしてOK!とすると査読が始まるみたい
先方でもビルドチェックがあるので,winduilderからメールが来ますが,これはた だの確認 査読が返ってきたら,コメントの通りに修正して再投稿! cran-comments.md に ## Resubmission のセクションを作って,どこを直し たか書いてあげるといい。 The way to CRAN 58 -
CRANの査読で言われたこと タイトルが冗長,Descriptionはもう少し詳細を書いて。 DESCRIPTIONファイルにある引用書式の修正 ヘルプファイルに戻り値が入ってないのがあるから,書き直すこと。戻り値がな い場合は,そのようにかくこと。 サンプルコードはなるべくつけるように。実行に5秒以上かかるようなら, \dontrun{} で囲っても良いが。 コンソールへの直接出力, print
や cat は避け, message , warning にせよ ユーザーのoptions, par, working directoryを変更してはいけない。変更が必要な場合 は、必ず on.exit() で元に戻すように The way to CRAN 59 -
再投稿していわれたこと 全てのサンプルコードが \donttest{} で囲まれているからテストできていない。 5秒以内で実行可能なサンプルコードは \donttest を外すこと。 ある関数, filename の引数が
"NULL" なので, "NULL" というファイルが生成さ れてしまう。引数のデフォルトはクォートを外して, NULL にせよ あとは再投稿せよ,というだけでした。 The way to CRAN 60 -
数日後 Thanks, on its way to CRAN. Best, Konstanze Lauseker
The way to CRAN 61 -
参考になるサイト一覧 Practical R Package Development roxygen2タグまとめ CRAN にパッケージを初投稿する手順 CRANにRパッケージを投稿するときの資料メモ CRANにパッケージを登録したのでその思い出をメモしておく
Rのパッケージ作成関連で最近気付いた(最近知った)ことの雑多なメモ あと,今日の話の簡単バージョンはこちら。 exametrika開発記#5 CRANに登録しよう The way to CRAN 63