>100 Views
April 05, 26
スライド概要
SAS言語を中心として,解析業務担当者・プログラマなのコミュニティを活性化したいです
R with Pharma Lab 「R」による ADaM 作成~ ADaM 作成の自動化への道~ 山崎 文寛 武田薬品工業株式会社 日本開発センター 生物統計室 2026/4/8
免責事項 • 本発表の内容は、「Rプログラミング言語」を活用したCDISC ADaMデータ作成に関する一般的な手法や考え方を説明するも のであり、特定のプロジェクトでの利用を保証するものではありません。 • 本発表に含まれるスクリプトや技術的手法は、参考目的で提示しております。適用する際には、必ず自身で内容を確認し、 プロジェクト要件やCDISC標準に合致することを確認してください。 • CDISC標準や規制要件については、適切なレビューや適合性の確認が必要です。 • 発表者個人の意見は、必ずしも所属組織やCDISC、その他の関連団体の公式見解を反映するものではありません。 2
本日の内容 1. pharmaverseにおけるADaM作成 2. 「R」によるADaM作成の自動化への道 3. まとめ 3
本日の内容 1. pharmaverseにおけるADaM作成 2. 「R」によるADaM作成の自動化への道 3. まとめ 4
pharmaverseの概要 • 製薬業界における臨床レポートを目的として「Rパッケージ」開発を促進する企業と個人のネットワーク • 各社・個人でのサイロ化した環境で、臨床レポーティング • 従来の重複的な取り組みから脱却し、共有ソリューションの採用により業務効率化 • 患者様に新しい治療法を迅速に提供 • CRF、SDTM/ADaM、解析結果のレポーティング、電子データ提出までをサポートする「Rパッケージ」の開発及びメンテナ ンスを実施 • 活動内容及び成果物はGitHub上で公開 • 5 例:admiral https://pharmaverse.github.io/admiral/cran-release/
pharmaverseパッケージ(データ作成関連を抜粋) <SDTM> <ADaM> ➢ sdtmchecks: SDTMのデータチェック ➢ admiral: ADaMの作成(コアパッケージ) ➢ datacutr: SDTMのカットオフ ➢ admiralonco: オンコロジー ➢ sdtm.oak: SDTMの作成 ➢ admiralophtha: 眼科 ➢ pharmaversesdtm: SDTMのテストデータ ➢ admiralvaccine: ワクチン ➢ 6 admiralpeds: 小児 ➢ admiralmetabolic: 代謝 ➢ admiralneuro: 神経科学 ➢ pharmaverseadam: ADaMのテストデータ <Metadata> ➢ metacore: Define.xml及びP21形式のExcelの読 込及び標準化されたオブジェクト (metacore オブジェクト) への保存 ➢ metatools: metacoreオブジェクトを使用して データセットを構築、拡張、チェック <eSub> ➢ xportr: SAS XPTファイルの作成 ➢ pkglite: 「Rパッケージ」のソース コードをテキスト化
pharmaverse ADaM Examplesについて • 7 pharmaverseで紹介されているADaM作成に関する内容 • ADaMの作成に使用する「Rパッケージ」 • metacore, metatools, admiral, xportr • データ分析用の「Rパッケージ」の集合であるtidyverse • ADaMデータセットごとのプログラミングフロー、サンプルデータ及び「R スクリプト」 • 対象データセット:ADSL, ADPC, ADPPK, ADRS, ADTTE, ADVS, ADAE • 例)ADSLのプログラミングフロー 1. SDTMデータセット等のソースデータと必要な「Rパッケージ」 の読み込み 2. SDTMデータセットにおける各変数の読み込み(SUPPXXの結合を 含む) 3. カテゴリ変数の導出(例:年齢のカテゴリ) 4. 投与情報及び解析対象集団に関する変数の作成 5. 投与群変数の作成 6. 投与の完了・中止及びその理由に関する変数の作成 7. 死亡に関する変数の作成 8. 他のカテゴリ変数の作成 9. 変数のチェック、ソート順の調整、XPTへの出力等 引用元:https://pharmaverse.github.io/examples/
pharmaverse admiralのページについて • • • • Get Started: ADSLを題材とした解説 Cheat Sheet: 機能の早見表 Explore ADaM Templates: ADaMテンプレートカタログ Presentation Archive: 過去のプレゼン 関数の詳細 • General Guides: プログラミングの概念とルール, 関数の種類, 高階関数 • ADaM Script Guides: ADaMの構造ごとの作成手順 • Special Topics Guides: 日時の補完, Analysis VisitやPeriodの導出, SMQなどの Queryデータの導出, CTCAEなどのグレーディングデータの適用 CRANにおける説明資料 GitHubへのリンク 問題点の報告 admiral関連のパッケージの説明 ADaMテンプレートカタログ (コードの確認が可能) ライセンス 問題の報告やコーディングによる貢献 コントリビューター・メンテナーの行 動規範 積極的に貢献した人たち 8
「Get Started」の活用 • admiralを活用してADaMデータセットを作成する手順を、実際に「Rスクリプト」を実行して学ぶことができる • 構成:目的 → セットアップ→ 導出関数 → その他の関数 → テンプレートを活用した「Rスクリプト」の作成開始 テストデータパッケージ「pharmaversesdtm」 9 関数の使用事例及びその実行結果 引用元: https://pharmaverse.github.io/admiral/cran-release/articles/admiral.html
「General Rules」はadmiralの基本 • プログラミングの概念とルール • • • • • 高階関数 • • • 10 admiralの関数を使用する際の入出力データの特徴 • 入力データのグループ化の解除、出力データがグループ化 されていないこと admiralの関数が入力値によってのみ決定される • データセット、変数名、その他オプションなどすべては引 数によって関数に渡される 欠測値の取り扱い • SASデータセットの読み込みにhavenパッケージを使用する 場合、SASの空白文字を「R」のNAに置き換える 「convert_blanks_to_na()」を使用 クォートとクォート解除 • rlangパッケージの「expr()」や「exprs()」を、スクリプト 内で式を評価せず、そのままの形で関数に引き渡すのに使 用(コードを文字列やデータとして扱う際に使用) call_derivation(): 単一の導出を複数回呼び出す(引数ごとに固 定・変更を実施) restrict_derivation(): 入力データの特定のレコードに対して単一の 導出 slice_derivation(): 上記2関数の組み合わせ • 導出関数の分類 以下の3つの特性で分類 1. 何を追加するか?(変数?レコード/パラメータ?) 2. ソースデータセットの数は?(単一?複数?) 3. 導出方法は何か?(選択?要約?計算?)
pharmaverse admiralの関数とチートシート admiralのよく使う関数を一気に見ることができる! • チートシートへのアクセス • パラメーターを追加する関数 R Studio → Help → Cheat Sheets → Browse Cheat Sheets… 日数・日付・日時等を追加する関数 変数を追加する関数 ベクトルに対する計算・変換等を行う関数 11 引用元:https://github.com/pharmaverse/admiral/blob/main/inst/cheatsheet/admiral_cheatsheet.pdf
pharmaverse admiralの関数とチートシート(続き) 特定の変数を追加する関数 高階関数 テンプレート 便利な関数 特定のパラメーターを 追加する関数 12 引用元:https://github.com/pharmaverse/admiral/blob/main/inst/cheatsheet/admiral_cheatsheet.pdf
本日の内容 1. pharmaverseにおけるADaM作成 2. 「R」によるADaM作成の自動化への道 3. まとめ 13
admiralの関数を使用
•
admiralの関数使用例
有害事象発現日(数値変
数)「ASTDT」の導出
admiralを「使わない」場合
admiralを「使う」場合
# dplyrを使用
adae <- ae %>%
mutate(
ASTDT = case_when(
str_detect(AESTDTC, "^\\d{4}-\\d{2}$") ~ as.Date(paste0(AESTDTC, "-01"), format = "%Y-%m-%d"),
TRUE ~ as.Date(substr(AESTDTC, 1, 10), format = "%Y-%m-%d")
)
)
adae <- ae %>% derive_vars_dt(
dtc = AESTDTC,
new_vars_prefix = "AST",
highest_imputation = "D“
)
admiralの関数を使うだけで、シンプルな「Rスクリプト」に!
•
14
admiralの関数を使う場合 / 使わない場合の比較
admiralを「使わない」場合
admiralを「使う」場合
コーディング負担
高(手作業が多く、一貫性や保守性に欠ける可能性がある)
低(処理ごとの専用関数により、一貫性があり、簡潔なスクリプトに
なる)
(利用者の)学習コスト
低(基本的な「R」の知識のみで良い)
「R」の経験が少ない場合はむしろ高くなる
高くはない(admiralの関数をチートシートや関数一覧などから探す必
要がある)
再利用性
困難(特定の状況や目的に特化)
簡単(変更箇所は関数の引数などが中心)
保守性
低(プログラマ間でのスクリプトの一貫性を確保しづらい)
高(関数を多用するため、メンテナンスや他者への引き継ぎも容易)
メタデータの活用 • メタデータ駆動型アプローチ • メタデータ(Excel形式のADaMの仕様書など)で、各データセット及び変数の属性、フォーマット、導出方法を定義しておき、それを 「R」に読み込んで、自動的にADaMを作成 • メリット • コードの再利用性がさらに高くなる • メタデータの変更により、別の試験にも適用可能 • ユーザーが「Rスクリプト」を直接触る必要がないため、エラーリスクが低減される • デメリット • 開発コスト(メタデータの設計・標準化及びメタデータ駆動が可能な「Rスクリプトの開発」) • 「Rスクリプト」のロジックが複雑で、トラブルシューティングに時間を要する可能性 • バリデーションの必要性 Rスクリプト (wrapper) Rスクリプト (各データセット 及び機能別) ADaM 実行 SDTM 15 メタデータ (ADaM仕様書等) データの流れ
メタデータの活用(続き) 1. admiraldiscoveryの活用<開発段階> • • • データセット、変数ごとに処理内容及び適用する関数を示した メタデータ • https://pharmaverse.github.io/admiraldiscovery/articles/react able.html 単一の関数で導出が可能な変数の場合に利用可能 現実的には組織、プロジェクトレベルで管理されるのが一般的 であり、どのような形でリリースされるかは不明 2. metacore/metatoolsの活用 • • Define.xml及びPinnacle 21形式のExcelファイルの情報を 「metacore」で「R」に取り込み、各変数の導出に利用可能 「metatools」には連続値からカテゴリ値を導出する関数もあ る 例)create_cat_var(data, metacore = spec, ref_var = AGE, grp_var = AGEGR1, num_grp_var = AGEGR1N) Pinnacle 21形式のExcelの「Codelists」を使用 <メタデータを活用したADaM作成フロー> SDTM メタデータ 16 「R」 ADaM
実装例1 既存のP21準拠のADaM Specをなるべく活用 1. メタデータの作成例(Pinnacle 21形式のADaMの仕様書) ➢ 「Variables」シート 2. 「R」へのメタデータの読み込み例 # Pinnacle 21形式のExcel仕様書を読み込む metacore <- spec_to_metacore(file.path(path$adam, "adam_spec.xlsx"), where_sep_sheet = FALSE) # ADSLのメタデータを抽出 adsl_spec <- metacore %>% select_dataset("ADSL") # 変数情報と導出情報を結合(元の仕様書と同様に データが分かれている) derivations_adsl <- left_join(adsl_spec$value_spec, adsl_spec$derivations, by="derivation_id") ➢ 「Methods」シート 17 Methodsの「Rスクリプト」への変換が課題 • そのまま読み込めるようにするか? • 何らかのルールに基づき変換するか?
実装例1(続き)
既存のP21準拠のADaM Specをなるべく活用
3. メタデータに基づき処理を実施する関数の定義例
process_mutate <- function(data, derivations, select_vars){
# derivationsに基づき動的にmutateを適用
data: 処理対象のデータフレーム
for (I in 1:nrow(derivations)) {
derivations: 導出情報を含むデータフレーム
var <- derivations$variable[i]
derivation_code <- derivations$derivation[i]
data <- data %>%
mutate(!!sym(var) := eval(parse(text = derivation_code)))
}
元々、文字情報として指定されていたデータを
#必要な変数を選択
「Rスクリプト」として実行
data_processed <- data %>%
select(all_of(select_vars))
return(data_processed)
}
4. 上記の関数を適用した変数の作成例
「Rスクリプト」にBMIを計算す
select_vars_vs <- c("STUDYID", "USUBJID", "BMIBL")
る数式自体は書いていない
filtered_deriv_vs <- derivations_adsl %>%
filter(variable %in% c("BMIBL"))
bmi <- process_mutate(adsl10, filtered_deriv_vs, select_vars_vs) %>%
create_cat_var(adsl_spec, BMIBL, BMIBLGR1)
18
実装例2
ルールはYAML、スクリプトは共通化
1. メタデータの作成例(YAML)
outputs:
datasets:
adsl:
base: "dm"
読みやすさ・書きやすさ
(インデントで階層を表現。
括弧やインデントが少ない。
複雑なタグ構造がない)
derivations:
ADSL:
- id: "AERELFL_from_AE"
method: "admiral::derive_var_merged_exist_flag"
args:
dataset: "dm"
dataset_add: "ae"
by_vars: ["STUDYID", "USUBJID"]
new_var: "AERELFL"
condition: 'AEREL == "PROBABLE"'
admiralの関数
- id: "WTBLHIFL_from_VS"
method: "admiral::derive_var_merged_exist_flag"
args:
dataset: "dm"
データの抽出
dataset_add: "vs"
by_vars: ["STUDYID", "USUBJID"]
filter_add: 'VSTESTCD == "WEIGHT" & VSBLFL == "Y"'
new_var: "WTBLHIFL"
condition: "VSSTRESN > 90"
false_value: "N"
フラグの条件
missing_value: "M"
19
2. 「R」へのメタデータの読み込み及び適用例
# YAMLファイルを読み込み、「R」のリスト形式に変換し、cfgに格納
cfg <- yaml::read_yaml(yaml_file)
# この時点で、左のメタデータの冒頭部分が「cfg$outputs$datasets$adsl$base」で参照可能に
なる。base_nameに「”dm”」を格納。
base_name <- cfg$outputs$datasets$adsl$base
# get()を使って「R」の環境からデータフレームを呼び出す。outに「dm」の実データを格納。
out <- get(base_name, envir = env)
# derivationsからADSLの導出定義のリストを取り出す (左記のメタデータは2つの定義がある)
derivs <- cfg$derivations$ADSL
# YAMLに書かれた順番に導出処理を適用 ※apply_one_derivationは次のページに記載
for (deriv in derivs) out <- apply_one_derivation(out, deriv, env)
実装例2(続き)
ルールはYAML、スクリプトは共通化
メタデータの作成例(YAML)※再掲
outputs:
datasets:
adsl:
base: "dm"
derivations:
ADSL:
- id: "AERELFL_from_AE"
method: "admiral::derive_var_merged_exist_flag"
args:
dataset: "dm"
dataset_add: "ae"
by_vars: ["STUDYID", "USUBJID"]
new_var: "AERELFL"
condition: 'AEREL == "PROBABLE"'
- id: "WTBLHIFL_from_VS"
method: "admiral::derive_var_merged_exist_flag"
args:
dataset: "dm"
dataset_add: "vs"
by_vars: ["STUDYID", "USUBJID"]
filter_add: 'VSTESTCD == "WEIGHT" & VSBLFL == "Y"'
new_var: "WTBLHIFL"
condition: "VSSTRESN > 90"
false_value: "N"
missing_value: "M"
20
3. YAMLの中身を解釈・実行
# 適用するadmiralの関数をmethodから取得
func <- resolve_fun(deriv$method)
# argsを取り出し、文字列→実オブジェクト・式に変換
args <- deriv$args
args$dataset_add <- get(args$dataset_add, envir = env)
args$by_vars <- as_exprs(args$by_vars)
exprs(!!!syms(...)) を使ってリスト
に変換し、式の中に展開
if (!is.null(args$condition)) args$condition <- as_opt_expr(args$condition)
if (!is.null(args$filter_add)) args$filter_add <- as_opt_expr(args$filter_add)
if (!is.null(args$new_var) && is.character(args$new_var)) {
args$new_var <- sym(args$new_var)
}
# 引数を渡して実行
args$dataset <- data
do.call(func, args)
parse_expr() で文字列を数
式に変換
本日の内容 1. pharmaverseにおけるADaM作成 2. 「R」によるADaM作成の自動化への道 3. まとめ 21
まとめ • 「R」によるADaM作成のメリット • • • • 22 オープンソース: コストが低く、新技術の実装が迅速 柔軟性と拡張性: 様々な「Rパッケージ」を活用した機能拡張 コミュニティのサポート: 先人たちが開発した「Rスクリプト」等の活用 「R」による効率化と自動化 • admiralパッケージの利用による効率化: • 既存のパッケージ・関数を最大限に活用することによる、社内プログラミングコストの低減。 • メタデータ駆動型アプローチ: • 便利なパッケージにおける関数を有効活用することを念頭に置き、それらの関数に試験ごとに異なる値を引き渡せるような外部の メタデータを整備する。 • 「Rスクリプト」は可能な限りシンプルな形として、自動化とエラーリスクの低減を両立させる。
参考文献 • admiral https://pharmaverse.github.io/admiral/cran-release/index.html • admiraldiscovery https://pharmaverse.github.io/admiraldiscovery/articles/reactable.html • Cheatsheets https://posit.co/resources/cheatsheets/ • metacore https://atorus-research.github.io/metacore/ • metatools https://pharmaverse.github.io/metatools/ • pharmaverse https://pharmaverse.org/ • R Submissions Working Group https://rconsortium.github.io/submissions-wg/ • R Validation Hub https://pharmar.org/ • 日本製薬工業協会 医薬品評価委員会 データサイエンス部会2023年度タスクフォース5「オープンソースソフトウェアの活用事例紹介」 https://www.jpma.or.jp/information/evaluation/results/allotment/DS_202406_OSS.html • 疫学のためのRハンドブック https://epirhandbook.com/jp/index.jp.html 23