本文へスキップ
からだにいいもの

Rのトピックスを中心に『まだ、まだ、知らない、役に立つ情報?』を発信します。

Rで解析:CDISC準拠のAnalysis Results Data(ARD)を構築する「cards」パッケージの紹介

医療やライフサイエンス分野では、臨床試験や研究の結果を正しく記録し共有することが重要です。膨大なデータを分析し、意味のある知見を得るためには、データの整理と可視化が必要不可欠です。本パッケージは臨床試験の結果を交換・再利用可能な形式に変換するだけでなく、サマリーテーブルやビジュアライゼーションを作成し、レポートを生成することができます。

なお、CDISCはClinical Data Interchange Standards Consortiumの略で、臨床試験データの交換や保存のための標準規格を定めている団体です。

CDISC | Clear Data. Clear Impact.

パッケージバージョンは0.8.1。Windows 11 x64 (build 26200)のR version 4.6.1で確認しています。

パッケージのインストール

下記コマンドを実行してください。

# パッケージのインストール
install.packages("cards")
# パッケージの読み込み
library("cards")

# コマンド例で必要なパッケージ
# install.packages("tidyverse")
library("tidyverse")
スポンサーリンク

コマンド例

詳細はコメント、パッケージのヘルプを確認してください。

ネストされたリストを結果データフレームの列に展開:.process_nested_list_as_dfコマンド

オプション意味初期値
x結果データフレーム
argネストされたリスト
new_column新しい列名を指定する
unlist完全な結果を解除するかどうかFALSE
# ADSLのデータを集計し、AGEGR1でグループ化する
ard <- ard_tabulate(ADSL, by = "ARM", variables = "AGEGR1")

# ネストされたリストを新しい列に展開する処理を行う
cards:::.process_nested_list_as_df(ard, NULL, "new_col")

実行結果:

group1 group1_level variable variable_level stat_name stat_label  stat
1     ARM      Placebo   AGEGR1            <65         n          n    14
2     ARM      Placebo   AGEGR1            <65         N          N    86
3     ARM      Placebo   AGEGR1            <65         p          % 0.163
4     ARM      Placebo   AGEGR1            >80         n          n    30
5     ARM      Placebo   AGEGR1            >80         N          N    86
6     ARM      Placebo   AGEGR1            >80         p          % 0.349
7     ARM      Placebo   AGEGR1          65-80         n          n    42
8     ARM      Placebo   AGEGR1          65-80         N          N    86
9     ARM      Placebo   AGEGR1          65-80         p          % 0.488
10    ARM   Xanomeli…   AGEGR1            <65         n          n    11

特定の変数にラベルを付与:ard_attributesコマンド

この関数を使用する場面では、データの特徴量や属性を理解し、分析や可視化の前処理として役立ちます。

オプション意味初期値
data(data.frame) データフレーム
variables(tidy-select) 含める変数を指定
label(named list) 変数ラベルを指定する名付けたリスト
# サンプルデータフレームを作成
df <- tibble(var1 = letters, var2 = LETTERS)
# var1列にラベル属性を設定
attr(df$var1, "label") <- "Lowercase Letters"

# 全ての変数の属性を取得
ard_attributes(df, variables = everything())

実行結果:

variable    context stat_name stat_label       stat fmt_fun
1     var1 attribut…     label Variable… Lowercas…    <fn>
2     var1 attribut…     class Variable…  character    NULL
3     var2 attribut…     label Variable…       var2    <fn>
4     var2 attribut…     class Variable…  character    NULL

階層的にネストされたタブレーションを実行:ard_hierarchical・ard_hierarchical_countコマンド

オプション意味初期値
data(data.frame) データフレーム
variables(tidy-select) 階層的(ネスト)集計を行う変数を指定
by(tidy-select) 集計の区分に使う変数を指定グループ化された変数
statistic(formula-list-selector) 形式のリストや単一の形式で、指定された要素が「n」、「N」、「p」、「n_cum」、「p_cum」のいずれかである場合
denominator(data.frame, integer) データフレームを使用して出力結果を定義し、分母を指定する。ard_hierarchical()では必須の引数、ard_hierarchical_count()では任意
fmt_fun(formula-list-selector) 形式のリストや単一の形式で、指定された要素が名付けたリストの関数である場合
stat_label(formula-list-selector) 形式のリストや単一の形式で、指定された要素が統計ラベルを定義する名付けたリストや形式のリストである場合
id(tidy-select) オプションの引数で、c(id, variables)列の組み合わせに重複がないことを確認する
fmt_fn非推奨の引数(fmt_funを使用)
# AESOC内でAEDECODを階層的に集計する(被験者ごとの最終レコードのみを使用)
ard_hierarchical(
  data = ADAE |>
    dplyr::slice_tail(n = 1L, by = c(USUBJID, TRTA, AESOC, AEDECOD)),
  variables = c(AESOC, AEDECOD),
  by = TRTA,
  id = USUBJID,
  denominator = ADSL
)

# AESOC・AEDECODの両方の階層について件数を集計する
ard_hierarchical_count(
  data = ADAE,
  variables = c(AESOC, AEDECOD),
  by = TRTA
)

実行結果:

   group1 group1_level group2 group2_level variable variable_level stat_name stat_label stat
1    TRTA      Placebo  AESOC   CARDIAC …  AEDECOD     ATRIAL F…         n          n    1
2    TRTA      Placebo  AESOC   CARDIAC …  AEDECOD     ATRIAL F…         n          n    0
3    TRTA      Placebo  AESOC   CARDIAC …  AEDECOD     ATRIAL H…         n          n    2
4    TRTA      Placebo  AESOC   CARDIAC …  AEDECOD     ATRIOVEN…         n          n    1
5    TRTA      Placebo  AESOC   CARDIAC …  AEDECOD     ATRIOVEN…         n          n    2
6    TRTA      Placebo  AESOC   CARDIAC …  AEDECOD     BRADYCAR…         n          n    4
7    TRTA      Placebo  AESOC   CARDIAC …  AEDECOD     BUNDLE B…         n          n    1
8    TRTA      Placebo  AESOC   CARDIAC …  AEDECOD     BUNDLE B…         n          n    2
9    TRTA      Placebo  AESOC   CARDIAC …  AEDECOD     CARDIAC …         n          n    0
10   TRTA      Placebo  AESOC   CARDIAC …  AEDECOD     CARDIAC …         n          n    1
…(以下略)

複数の変数の統計量をまとめて計算:ard_mvsummaryコマンド

オプション意味初期値
data(data.frame) データフレーム
variables要約する列の選択
by集計の区分に使う列を指定;未観測の組み合わせ・因子水準も含めた全ての組み合わせについて結果が計算される
strata集計の層別に使う列を指定;byと併用可能。実際に観測された組み合わせについてのみ結果が計算されるNULL
statistic統計量を計算する関数を指定;関数はx、data、full_data、by、strataを引数として受け取れるよう定義する(”…”を含めることを推奨)
fmt_fun(formula-list-selector) 形式のリストや単一の形式で、指定された要素が名付けたリストの関数である場合
stat_label統計ラベルを定義する式のリスト
fmt_fn非推奨の引数(fmt_funを使用)
# ard_summary()と同じ挙動を再現する例
ard_mvsummary(
  ADSL,
  by = "ARM",
  variables = "AGE",
  statistic = list(AGE = list(mean = \(x, ...) mean(x)))
)

# グループ内平均と全体平均の両方を返す関数を定義
grand_mean <- function(data, full_data, variable, ...) {
  list(
    mean = mean(data[[variable]], na.rm = TRUE),
    grand_mean = mean(full_data[[variable]], na.rm = TRUE)
  )
}

# ARMでグループ化し、グループ内平均と全体平均を計算する
ADSL |>
  dplyr::group_by(ARM) |>
  ard_mvsummary(
    variables = "AGE",
    statistic = list(AGE = list(means = grand_mean))
  )

実行結果:

group1 group1_level variable stat_name stat_label   stat
1    ARM      Placebo      AGE      mean       Mean 75.209
2    ARM   Xanomeli…      AGE      mean       Mean 74.381
3    ARM   Xanomeli…      AGE      mean       Mean 75.667
  group1 group1_level variable  stat_name stat_label   stat
1    ARM      Placebo      AGE       mean       Mean 75.209
2    ARM      Placebo      AGE grand_mean grand_me… 75.087
3    ARM   Xanomeli…      AGE       mean       Mean 74.381
4    ARM   Xanomeli…      AGE grand_mean grand_me… 75.087
5    ARM   Xanomeli…      AGE       mean       Mean 75.667
6    ARM   Xanomeli…      AGE grand_mean grand_me… 75.087

エラー発生時もARDの構造を保つ関数ラッパーを作成:as_cards_fnコマンド

オプション意味初期値
f関数の指定
stat_names期待される統計名の指定
# エラーが起きない場合、as_cards_fn()を使わない場合と同じ結果になる
ttest_works <-
  as_cards_fn(
    \(x) t.test(x)[c("statistic", "p.value")],
    stat_names = c("statistic", "p.value")
  )
ard_summary(
  mtcars,
  variables = mpg,
  statistic = ~ list(ttest = ttest_works)
)

# エラーが発生してもas_cards_fn()を使っていれば、
# エラーが起きなかった場合と同じ構造の結果が得られる
ttest_error <-
  as_cards_fn(
    \(x) {
      t.test(x)[c("statistic", "p.value")]
      stop("Intentional Error")
    },
    stat_names = c("statistic", "p.value")
  )
ard_summary(
  mtcars,
  variables = mpg,
  statistic = ~ list(ttest = ttest_error)
)

# as_cards_fn()を使わずにエラーが発生した場合、
# 返される結果は1行のみになる
ard_summary(
  mtcars,
  variables = mpg,
  statistic = ~ list(ttest = \(x) {
    t.test(x)[c("statistic", "p.value")]
    stop("Intentional Error")
  })
)

実行結果:

variable context stat_name stat_label   stat fmt_fun
1      mpg summary statistic  statistic 18.857       1
2      mpg summary   p.value    p.value      0       1
  variable context stat_name stat_label stat      error
1      mpg summary statistic  statistic      Intentio…
2      mpg summary   p.value    p.value      Intentio…
  variable context stat_name stat_label stat      error
1      mpg summary     ttest      ttest      Intentio…

非推奨関数shuffle_ard()でARDオブジェクトを整理する:shuffle_ardコマンド

オプション意味初期値
xARDデータフレームの指定
trim統計値のメタデータを削除し、数値の統計量のみに絞り込むかどうかの指定TRUE
# 2つのARDを結合する
bind_ard(
  ard_tabulate(ADSL, by = "ARM", variables = "AGEGR1"),
  ard_tabulate(ADSL, variables = "ARM")
) |>
  # 結合したARDを整理する(非推奨関数)
  shuffle_ard()

実行結果:

# A tibble: 36 × 7
   ARM               variable variable_level context stat_name stat_label   stat
   <chr>             <chr>    <chr>          <chr>   <chr>     <chr>       <dbl>
 1 Placebo           AGEGR1   <65            tabula… n         n          14
 2 Placebo           AGEGR1   <65            tabula… N         N          86
 3 Placebo           AGEGR1   <65            tabula… p         %           0.163
 4 Placebo           AGEGR1   >80            tabula… n         n          30
 5 Placebo           AGEGR1   >80            tabula… N         N          86
 6 Placebo           AGEGR1   >80            tabula… p         %           0.349
 7 Placebo           AGEGR1   65-80          tabula… n         n          42
 8 Placebo           AGEGR1   65-80          tabula… N         N          86
 9 Placebo           AGEGR1   65-80          tabula… p         %           0.488
10 Xanomeline High … AGEGR1   <65            tabula… n         n          11
# ℹ 26 more rows

n・N・pなどのタブレーション統計量を計算:.calculate_tabulation_statisticsコマンド

オプション意味初期値
data(data.frame) データフレーム
variables要約する列の選択everything()
by集計の区分に使う列を指定;未観測の組み合わせ・因子水準も含めた全ての組み合わせについて集計される
strata集計の層別に使う列を指定;byと併用可能。実際に観測された組み合わせについてのみ集計される
denominator分母を変更するための引数。例えば「N」統計量の算出方法を指定する‘column’
statistic(formula-list-selector) 形式のリストや単一の形式で、指定された要素が「n」、「N」、「p」、「n_cum」、「p_cum」のいずれかである場合
# ARM列の件数(N)をタブレーション統計として計算する
cards:::.calculate_tabulation_statistics(
  ADSL,
  variables = "ARM",
  by = NULL,
  strata = NULL,
  denominator = "cell",
  statistic = list(ARM = list(tabulation = c("N")))
)

実行結果:

# A tibble: 3 × 6
  variable variable_level stat_name stat      warning error
  <chr>    <list>         <chr>     <list>    <list>  <list>
1 ARM      <chr [1]>      N         <int [1]> <NULL>  <NULL>
2 ARM      <chr [1]>      N         <int [1]> <NULL>  <NULL>
3 ARM      <chr [1]>      N         <int [1]> <NULL>  <NULL>

「..cards_overall..」等のプレースホルダーを表示用ラベルに変換:.derive_overall_labelsコマンド

オプション意味初期値
x対象の現在の列内容
cur_col現在の列名dplyr::cur_column()
# プレースホルダーを含むサンプルデータを作成
data <- dplyr::tibble(
  ARM = c("..cards_overall..", "Overall ARM", NA, "BB", NA),
  TRTA = c(NA, NA, "..hierarchical_overall..", "C", "C")
)

# 各列のプレースホルダーを表示用ラベルに変換する
data |>
  dplyr::mutate(
    dplyr::across(
      ARM:TRTA,
      cards:::.derive_overall_labels
    )
  )

実行結果:

# A tibble: 5 × 2
  ARM           TRTA
  <chr>         <chr>
1 Overall ARM.1 <NA>
2 Overall ARM   <NA>
3 <NA>          Any TRTA
4 BB            C
5 <NA>          C


この記事が誰かの役に立ちますように。

スポンサーリンク
Prices and shipping availability may change. Please refer to the product page at time of purchase.
Content displayed on this site is provided by Amazon and may be updated or removed.
Amazon Associate, karada-good earns income through qualifying sales.