臨床検査における評価者間信頼性は、検査結果の再現性と妥当性を確保するために極めて重要です。本記事では、エコー検査による肝腎コントラスト測定の評価者間信頼性を3人の臨床検査技師で検討する研究デザインとその解析方法について説明します。 ## 研究デザイン 3人の評価者による実用的な研究デザインを採用します: - 各患者は2人の臨床検査技師によって評価される - 合計3人の臨床検査技師が研究に参加する - 総計30人の患者データを収集する - 各評価者ペアに10人ずつ割り当てる ## 評価者の組み合わせ 3人の評価者から作れるペアは3組です: 1. 評価者1-2 2. 評価者2-3 3. 評価者3-1 この設計では、全ての評価者が他の2人の評価者と比較されるため、完全な評価者間一致度の評価が可能です。 ## パッケージのインストール 福井大学では、学内から R のパッケージをインストールできません。インストール使用とすると途中で止まります。 そのため、Rコードの最初に以下のコードを貼り付けておくことでエラーを回避できます。 ```R # プロキシの設定 Sys.setenv(http_proxy="http://ufproxy.m.cii.u-fukui.ac.jp:8080/") Sys.setenv(https_proxy="http://ufproxy.m.cii.u-fukui.ac.jp:8080/") ``` パッケージ `psych` と `lme4` は事前にインストールしておいてください。 ```R install.packages("psych") install.packages("lme4") ``` ## 全体コード **注意**: 本記事では解説のためにサンプルデータを直接コードに入力していますが、実際の研究では事前にExcelで作成したデータを読み込んで解析を行います。 ```R # データ削除(データが消えてしまうので注意) rm(list=ls()) # 必要なパッケージの読み込み library(psych) library(lme4) # 実際の研究では以下のようにExcelファイルを読み込みます # library(readxl) # data_long <- read_excel("肝腎コントラスト測定データ.xlsx") # 本記事では解説用にサンプルデータを作成します # 臨床検査技師3人による肝腎コントラスト測定データ # 各患者は2人の技師によって評価される # データ形式: 患者ID、評価者ID、肝腎コントラスト値 # サンプルデータの作成(実際の研究では上記のread_excelを使用) data_long <- data.frame( patient_id = c( # 患者1-10: 各患者2回の測定 rep(1:10, each=2), # 患者11-20: 各患者2回の測定 rep(11:20, each=2), # 患者21-30: 各患者2回の測定 rep(21:30, each=2) ), rater_id = c( # 患者1-10: 技師1と2のペア rep(c(1,2), times=10), # 患者11-20: 技師2と3のペア rep(c(2,3), times=10), # 患者21-30: 技師3と1のペア rep(c(3,1), times=10) ), liver_kidney_contrast = c( # 患者1-10: 技師1と2のデータ(技師間の測定値にばらつきを考慮) 1.35,1.42, 1.42,1.35, 1.23,1.29, 1.54,1.48, 1.41,1.38, 1.26,1.31, 1.44,1.39, 1.18,1.24, 1.37,1.43, 1.51,1.46, # 患者11-20: 技師2と3のデータ 1.49,1.42, 1.33,1.39, 1.45,1.40, 1.29,1.35, 1.50,1.44, 1.36,1.41, 1.22,1.28, 1.49,1.43, 1.34,1.40, 1.46,1.52, # 患者21-30: 技師3と1のデータ 1.27,1.33, 1.39,1.32, 1.24,1.30, 1.51,1.45, 1.31,1.37, 1.43,1.48, 1.29,1.35, 1.52,1.46, 1.38,1.44, 1.45,1.39 ) ) # データの確認 print("データの先頭10行:") head(data_long, 10) # 評価者組み合わせの頻度を確認 cat("\n各評価者ペアの患者数:\n") pair_counts <- table(paste0( data_long$rater_id[seq(1, nrow(data_long), 2)], "-", data_long$rater_id[seq(2, nrow(data_long), 2)])) print(pair_counts) # 評価者ペアごとの一致度分析 cat("\n評価者ペアごとの一致度:\n") pairs <- list(c(1,2), c(2,3), c(3,1)) for(pair in pairs) { # このペアのデータを抽出 pair_data <- data_long[data_long$rater_id %in% pair, ] # データをwide形式に変換 pair_wide <- reshape(pair_data, idvar = "patient_id", timevar = "rater_id", direction = "wide") # 評価者の列を抽出 rater_cols <- grep("liver_kidney_contrast", colnames(pair_wide)) # ICCを計算 icc_data <- pair_wide[, rater_cols] colnames(icc_data) <- c(paste0("rater", pair[1]), paste0("rater", pair[2])) icc_result <- ICC(icc_data) cat(paste0("評価者 ", pair[1], " と評価者 ", pair[2], " の ICC(2,1): ", round(icc_result$results[2, "ICC"], 3), " [95%CI: ", round(icc_result$results[2, "lower bound"], 3), "-", round(icc_result$results[2, "upper bound"], 3), "]", " (n=", nrow(icc_data), ")\n")) } # 【推奨】混合効果モデルによる全体の評価者間信頼性の推定 library(lme4) # 混合効果モデル:評価者を固定効果、患者をランダム効果として扱う mixed_model <- lmer(liver_kidney_contrast ~ rater_id + (1|patient_id), data = data_long) # 分散成分を抽出 variance_components <- as.data.frame(VarCorr(mixed_model)) patient_variance <- variance_components[1, "vcov"] # 患者間分散 residual_variance <- variance_components[2, "vcov"] # 残差分散(評価者内分散) # ICC(2,1)を計算:患者間分散 / (患者間分散 + 残差分散) mixed_icc <- patient_variance / (patient_variance + residual_variance) cat("\n【推奨】混合効果モデルによる全体ICC(2,1): ", round(mixed_icc, 3), "\n") # ICC用のブートストラップ関数を定義 calc_icc <- function(model) { vc <- as.data.frame(VarCorr(model)) patient_var <- vc[1, "vcov"] residual_var <- vc[2, "vcov"] return(patient_var / (patient_var + residual_var)) } # ブートストラップによる95%信頼区間の計算(時間がかかる場合があります) cat("\nブートストラップによる95%信頼区間を計算中...\n") boot_icc <- bootMer(mixed_model, calc_icc, nsim = 200) icc_ci <- quantile(boot_icc$t, c(0.025, 0.975)) cat("混合効果モデルによる全体ICC(2,1): ", round(mixed_icc, 3), " [95%CI: ", round(icc_ci[1], 3), "-", round(icc_ci[2], 3), "]\n") # モデルの詳細を表示(オプション) cat("\n混合効果モデルの分散成分:\n") print(variance_components) # 【参考】全ペアの平均ICC(理解が難しい場合はこちらを参照) cat("\n-----------------------------------\n") cat("【参考】ペア別ICCの単純平均(上記と近似値):\n") all_iccs <- numeric(0) all_lower <- numeric(0) all_upper <- numeric(0) for(pair in pairs) { # このペアのデータを抽出して処理 pair_data <- data_long[data_long$rater_id %in% pair, ] pair_wide <- reshape(pair_data, idvar = "patient_id", timevar = "rater_id", direction = "wide") rater_cols <- grep("liver_kidney_contrast", colnames(pair_wide)) icc_data <- pair_wide[, rater_cols] colnames(icc_data) <- c(paste0("rater", pair[1]), paste0("rater", pair[2])) icc_result <- ICC(icc_data) all_iccs <- c(all_iccs, icc_result$results[2, "ICC"]) all_lower <- c(all_lower, icc_result$results[2, "lower bound"]) all_upper <- c(all_upper, icc_result$results[2, "upper bound"]) } # 平均ICC値と95%信頼区間の範囲を計算 mean_icc <- mean(all_iccs) mean_lower <- mean(all_lower) mean_upper <- mean(all_upper) cat("ペア別ICC平均: ", round(mean_icc, 3), " [95%CI: ", round(mean_lower, 3), "-", round(mean_upper, 3), "]\n") cat("(注:統計学的にはより厳密な混合効果モデルの結果を採用することを推奨)\n") # 補足情報: 各評価者の評価患者数 cat("\n補足情報: 各評価者の評価患者数:\n") rater_patient_counts <- table(data_long$rater_id) print(rater_patient_counts) ``` ## コードブロック毎の解説 ### 1. 環境設定とパッケージ読み込み ```R # プロキシの設定(福井大学内での実行時に必要) Sys.setenv(http_proxy="http://ufproxy.m.cii.u-fukui.ac.jp:8080/") Sys.setenv(https_proxy="http://ufproxy.m.cii.u-fukui.ac.jp:8080/") # データ削除(データが消えてしまうので注意) rm(list=ls()) # 必要なパッケージの読み込み library(psych) ``` このブロックでは、福井大学のプロキシ設定を行い、作業環境をクリアして、ICC計算に必要な`psych`パッケージと混合効果モデルに必要な`lme4`パッケージを読み込みます。 混合効果モデルでは、評価者を固定効果(決まった3人の評価者)、患者をランダム効果として扱います。ランダム効果とは、「同じ患者さんから得られた2人の評価者のデータは互いに関連している」ということをモデルに織り込むことです。例えば、肝腎コントラストが高い患者さんを測定した場合、2人の評価者とも高い値を測定するはずだということを考慮します。 ### 2. データ作成(実際の研究では外部ファイル読み込み) ```R # 実際の研究では以下のようにExcelファイルを読み込みます # library(readxl) # data_long <- read_excel("肝腎コントラスト測定データ.xlsx") # 本記事では解説用にサンプルデータを作成します data_long <- data.frame( patient_id = c( rep(1:10, each=2), rep(11:20, each=2), rep(21:30, each=2) ), rater_id = c( rep(c(1,2), times=10), rep(c(2,3), times=10), rep(c(3,1), times=10) ), liver_kidney_contrast = c( # 技師間の測定値にばらつきを考慮したデータ 1.35,1.42, 1.42,1.35, # ... 以下省略 ) ) ``` 実際の研究では、Excelで作成したデータファイルを読み込みます。本記事では解説のため30人の患者データを直接作成していますが、各患者について2人の評価者による測定値を設定し、評価者間のばらつきを現実的にするため、測定値に適度な差異を設けています。 ### 3. データ確認と集計 ```R # データの確認 print("データの先頭10行:") head(data_long, 10) # 評価者組み合わせの頻度を確認 cat("\n各評価者ペアの患者数:\n") pair_counts <- table(paste0( data_long$rater_id[seq(1, nrow(data_long), 2)], "-", data_long$rater_id[seq(2, nrow(data_long), 2)])) print(pair_counts) ``` 作成したデータの構造を確認し、各評価者ペアが担当する患者数を集計します。 ### 4. 評価者ペアごとのICC計算 ```R # 評価者ペアごとの一致度分析 cat("\n評価者ペアごとの一致度:\n") pairs <- list(c(1,2), c(2,3), c(3,1)) for(pair in pairs) { # このペアのデータを抽出 pair_data <- data_long[data_long$rater_id %in% pair, ] # データをwide形式に変換 pair_wide <- reshape(pair_data, idvar = "patient_id", timevar = "rater_id", direction = "wide") # ICCを計算 rater_cols <- grep("liver_kidney_contrast", colnames(pair_wide)) icc_data <- pair_wide[, rater_cols] colnames(icc_data) <- c(paste0("rater", pair[1]), paste0("rater", pair[2])) icc_result <- ICC(icc_data) # 結果を出力 cat(paste0("評価者 ", pair[1], " と評価者 ", pair[2], " の ICC(2,1): ", round(icc_result$results[2, "ICC"], 3), " [95%CI: ", round(icc_result$results[2, "lower bound"], 3), "-", round(icc_result$results[2, "upper bound"], 3), "]", " (n=", nrow(icc_data), ")\n")) } ``` 各評価者ペアについて、長形式データを wide形式に変換してから ICC(2,1) を計算し、ICC値の95%信頼区間とともに結果を表示します。 ### 5. 【推奨】混合効果モデルによる全体的な評価者間信頼性 ```R # 【推奨】混合効果モデルによる全体の評価者間信頼性の推定 library(lme4) # 混合効果モデル:患者を随意効果、評価者を固定効果として扱う mixed_model <- lmer(liver_kidney_contrast ~ rater_id + (1|patient_id), data = data_long) # 分散成分を抽出 variance_components <- as.data.frame(VarCorr(mixed_model)) patient_variance <- variance_components[1, "vcov"] # 患者間分散 residual_variance <- variance_components[2, "vcov"] # 残差分散(評価者内分散) # ICC(2,1)を計算:患者間分散 / (患者間分散 + 残差分散) mixed_icc <- patient_variance / (patient_variance + residual_variance) # ICC用のブートストラップ関数を定義 calc_icc <- function(model) { vc <- as.data.frame(VarCorr(model)) patient_var <- vc[1, "vcov"] residual_var <- vc[2, "vcov"] return(patient_var / (patient_var + residual_var)) } # ブートストラップによる95%信頼区間の計算(時間がかかる場合があります) cat("\nブートストラップによる95%信頼区間を計算中...\n") boot_icc <- bootMer(mixed_model, calc_icc, nsim = 200) icc_ci <- quantile(boot_icc$t, c(0.025, 0.975)) cat("混合効果モデルによる全体ICC(2,1): ", round(mixed_icc, 3), " [95%CI: ", round(icc_ci[1], 3), "-", round(icc_ci[2], 3), "]\n") ``` このアプローチでは、線形混合効果モデルを使用して、不完全な評価者設計(すべての評価者がすべての患者を評価しない設計)に適した信頼性推定を行います。 評価者を固定効果、患者をランダム効果として扱うことで、「同じ患者さんのデータは関連している」ということを適切にモデルに組み込めます。つまり、肝腎コントラストが本当に高い患者さんであれば、どの評価者が測定しても高い値になるはずで、逆に低い患者さんであればどの評価者も低い値を測定するはずです。このような患者さん特有の特徴を考慮することで、より正確な評価者間信頼性を推定できます。95%信頼区間はブートストラップ法により計算されます。 ### 6. 【参考】ペア別ICCの単純平均(理解が困難な場合の参考値) ```R # 【参考】全ペアのICCの平均値と95%信頼区間を計算 # (混合効果モデルの理解が困難な場合は、この近似値を参考にしても構いません) all_iccs <- numeric(0) all_lower <- numeric(0) all_upper <- numeric(0) for(pair in pairs) { # 各ペアのICCと信頼区間を計算して配列に格納 pair_data <- data_long[data_long$rater_id %in% pair, ] pair_wide <- reshape(pair_data, idvar = "patient_id", timevar = "rater_id", direction = "wide") rater_cols <- grep("liver_kidney_contrast", colnames(pair_wide)) icc_data <- pair_wide[, rater_cols] colnames(icc_data) <- c(paste0("rater", pair[1]), paste0("rater", pair[2])) icc_result <- ICC(icc_data) all_iccs <- c(all_iccs, icc_result$results[2, "ICC"]) all_lower <- c(all_lower, icc_result$results[2, "lower bound"]) all_upper <- c(all_upper, icc_result$results[2, "upper bound"]) } # 平均ICC値と95%信頼区間の範囲を計算 mean_icc <- mean(all_iccs) mean_lower <- mean(all_lower) mean_upper <- mean(all_upper) cat("ペア別ICC平均: ", round(mean_icc, 3), " [95%CI: ", round(mean_lower, 3), "-", round(mean_upper, 3), "]\n") cat("(注:統計学的にはより厳密な混合効果モデルの結果を採用することを推奨)\n") ``` この方法は統計学的には最適ではありませんが、混合効果モデルの結果とほぼ同様の値が得られるため、理解が困難な場合の参考値として使用できます。ただし、学術的な報告では混合効果モデルの結果を採用することを強く推奨します。 ### 7. 補足情報の表示 ```R # 補足情報: 各評価者の評価患者数 cat("\n補足情報: 各評価者の評価患者数:\n") rater_patient_counts <- table(data_long$rater_id) print(rater_patient_counts) ``` 各評価者が評価した患者数を集計し、負荷の均等性を確認します。 ## 実行結果例 このコードを実行すると、以下のような結果が得られます: ``` データの先頭10行: patient_id rater_id liver_kidney_contrast 1 1 1 1.35 2 1 2 1.42 3 2 1 1.42 4 2 2 1.35 5 3 1 1.23 6 3 2 1.29 7 4 1 1.54 8 4 2 1.48 9 5 1 1.41 10 5 2 1.38 各評価者ペアの患者数: 1-2 2-3 3-1 10 10 10 評価者ペアごとの一致度: 評価者 1 と評価者 2 の ICC(2,1): 0.791 [95%CI: 0.609-0.895] (n=30) 評価者 2 と評価者 3 の ICC(2,1): 0.748 [95%CI: 0.538-0.871] (n=30) 評価者 3 と評価者 1 の ICC(2,1): 0.762 [95%CI: 0.56-0.879] (n=30) 混合効果モデルによる全体ICC(2,1): 0.761 [95%CI: 0.574 - 0.879 ] ----------------------------------- 【参考】ペア別ICCの単純平均(上記と近似値): ペア別ICC平均: 0.767 [95%CI: 0.569 - 0.881 ] (注:統計学的にはより厳密な混合効果モデルの結果を採用することを推奨) 補足情報: 各評価者の評価患者数: 1 2 3 20 20 20 ``` ## 考察 3人の評価者による環状設計の利点: **バランスの良い設計**: 各評価者が20人の患者を評価し、各評価者ペアが10人ずつ担当することで、均等な負荷分散が実現されています。 **完全な比較**: 3人の評価者すべてが相互に比較されるため、どの評価者間でも一致度を評価できます。 **効率性**: 最小限のペア数(3組)で全体の評価者間信頼性を評価できます。 **統計学的妥当性**: 混合効果モデルを用いることで、評価者の重複や系統的な偏りを適切に考慮した信頼性推定が可能です。 **結果の解釈**: 混合効果モデルによる全体ICC値は、エコーによる肝腎コントラスト測定が3人の臨床検査技師間で「良好な信頼性」を持つことを示しています。この値は、ペア別ICC平均とほぼ同じですが、より正確な推定値です。 分散成分の結果を見ると、患者間の値(`0.0057`)が評価者による測定のばらつき(`0.0017`)よりもずっと大きいことが分かります。これは、測定値の違いのほとんどが「本当の患者さん同士の違い」によるもので、「技師による測定のばらつき」は小さいということを意味します。つまり、どの技師が測定しても似たような結果が得られるということです。 ## 参考 - `psych` [CRAN レポジトリへのリンク](https://cran.r-project.org/web/packages/psych/index.html) - [CRANリポジトリの PDFマニュアル](https://cran.r-project.org/web/packages/psych/psych.pdf) - [psych 作者のホームページ](https://personality-project.org/r/psych/)