Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CRANへの道

 CRANへの道

ベイズ統計学勉強回春'24で発表した資料です。
私が開発したexametrikaパッケージをCRANに登録した時のノウハウについて解説してます。

Koji E. Kosugi

February 23, 2025
Tweet

More Decks by Koji E. Kosugi

Other Decks in Programming

Transcript

  1. 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
  2. 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
  3. 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
  4. フォルダ構成はこうせい 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
  5. 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
  6. DESCRIPTIONを書く時の注意 依存関係(自分のパッケージが使うパッケージ)を全部書く。 Rのバージョンにも注意( |> はR>=4.1) Roxygen のバージョンもローカルのバージョンとあってるように。 著者情報の書き方は,名前,役割(下記参照),メアドなど。 "aut" (author)

    : パッケージの主要な作者 "cre" (creator) : パッケージのメンテナ(連絡担当者) "ctb" (contributor) : コードやドキュメントの貢献者 "cph" (copyright holder) : 著作権保持者 c() を使って複数の著者をかくこともできます。 The way to CRAN 20
  7. Roxygenで書こう ヘルプファイルやNAME SPACEを自動でまとめてくれるから,パッケージづくりは楽 になった! #' で始める基本構造 #' @title 関数のタイトル #'

    @description 関数の説明 #' @param x 引数の説明 #' @return 返り値の説明 #' @export #' my_function <- function(x) { # 関数の中身 } The way to CRAN 23
  8. Roxygen 主要タグ #' @param name 引数の説明。関数で使われている引数が全て含まれていないと, エラーになる #' @return 返り値の説明。

    #' @examples 使用例を記述。後述するが,CRANに登録する際はこれを結構書く ように勧められる。 #' @export これがないと関数はパッケージ内からしか参照できず,ユーザは使え ない #' @keywords internal 逆にユーザに触らせないのであればinternalに指定 The way to CRAN 24
  9. Roxygen 主要タグ2 #' @importFrom stats mean var 他パッケージから関数をインポートしてくるときは,パッケージ名と関数を列挙。不 足があればエラーになります。 #'

    @details 詳細な説明 #' @seealso ここも見てね,みたいなのがあれば便利 #' @references 出典があれば書いておこう The way to CRAN 25
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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
  15. まずはデフォルトで通す関数を作る #' @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
  16. あとは分岐先の関数を作る #' @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
  17. 手順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
  18. テストの書き方 テストファイルは独立環境なので,ライブラリの読み込みなどが必要(現実行環境 と同じではない) test_that() で検証したいテストをくくる 最初にテスト名を "テスト名" として入力。出力時にどの関数・どの数字をテスト してるか確認するため {}

    内にRコードを。これは特殊な書き方はしない 期待値との照合は expect_equal() や expect_identical() を使う。後者の方が 厳密な一致で,前者は許容誤差( tolerance )を設定可能 機能ごとに別のファイルにしておこう。 The way to CRAN 42
  19. 手順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
  20. 手順11. またせたな,CRAN じゃあそろそろCRANにも載せてもらいましょう。 library 関数で自分のパッケージ が出てくるなんて胸熱! もう一度いろいろチェックしよう styler::style_pkg() でコード整形 devtools::check()

    でローカルチェック devtools::spell_check() でスペルチェック 生成されるドキュメントの中に,ミススペルがないかチェックする 専門用語・略語もエラーとして出てくるので, inst/WORDLIST に回避する用 語を書き込んでおこう The way to CRAN 49
  21. 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
  22. 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
  23. 手順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
  24. 手順12. いよいよCRANへ devtools::release() で投稿〜! まず Confirmation Linkが送られてくる。 「投稿したよな?確認のためにサイトに来 てチェックして」と言われる。 いくつかの了承事項をチェックしてOK!とすると査読が始まるみたい

    先方でもビルドチェックがあるので,winduilderからメールが来ますが,これはた だの確認 査読が返ってきたら,コメントの通りに修正して再投稿! cran-comments.md に ## Resubmission のセクションを作って,どこを直し たか書いてあげるといい。 The way to CRAN 58
  25. 再投稿していわれたこと 全てのサンプルコードが \donttest{} で囲まれているからテストできていない。 5秒以内で実行可能なサンプルコードは \donttest を外すこと。 ある関数, filename の引数が

    "NULL" なので, "NULL" というファイルが生成さ れてしまう。引数のデフォルトはクォートを外して, NULL にせよ あとは再投稿せよ,というだけでした。 The way to CRAN 60
  26. 参考になるサイト一覧 Practical R Package Development roxygen2タグまとめ CRAN にパッケージを初投稿する手順 CRANにRパッケージを投稿するときの資料メモ CRANにパッケージを登録したのでその思い出をメモしておく

    Rのパッケージ作成関連で最近気付いた(最近知った)ことの雑多なメモ あと,今日の話の簡単バージョンはこちら。 exametrika開発記#5 CRANに登録しよう The way to CRAN 63