no55 tokyo r_presentation

Post on 13-Apr-2017

319 Views

Category:

Data & Analytics

4 Downloads

Preview:

Click to see full reader

TRANSCRIPT

第 55 回  勉強会 @ 東京 (#TokyoR) 30/07/2016

Cutoff 値は自分で決めたい~生存時間分析と ROC curve

@fuuuumin314

自己紹介• ID : @fuuuumin314

• 大学 5 年生• R との関わり:主に研究室のデータ分析ツールとして利用• R ユーザー歴: 1 年(初心者)• TokyoR 参加: 2 回目

注意• もともと統計、機械学習、 R は独学なので間違い、改良点がございましたらご指摘いただけると幸いです

今回使うデータ• Melanoma data {MASS}• 205 件のデンマーク人の悪性黒色腫生存データ• 生存期間、年齢、性別、隆起の厚さ (mm) 、潰瘍の有無

今回使うデータ• Melanoma data {MASS}• 205 件のデンマーク人の悪性黒色腫生存データ• 生存期間、年齢、性別、隆起の厚さ (mm) 、潰瘍の有無

www.skincancer.org

パッケージ紹介• library(ggplot2)  ← 作図おなじみ• library(dplyr)  ← 前処理おなじみ• library(MASS)  ← データ、 step wise AIC• library(survival)  ← 生存時間分析• library(survminer) ←  生存時間プロット• library(survivalROC)  ← 生存時間分析 ROC

前処理## reading and preparing datadf <- Melanomadf$status <- as.factor(df$status)df$ulcer <- as.factor(df$ulcer)df1 <- df %>% ## excluding cases dplyr::filter(!(status == 3)) %>% ## alive = 0, dead = 1 dplyr::mutate(cens = ifelse(status == 1, 1, 0))df1$cens <- as.integer(df1$cens)

>head(df1)> head(df1) time status sex age year thickness ulcer cens1 35 2 1 41 1977 1.34 0 02 185 1 1 52 1965 12.08 1 13 204 1 1 28 1971 4.84 1 14 210 1 1 77 1972 5.16 1 15 232 1 1 49 1968 12.88 1 16 279 1 0 68 1971 7.41 1 1

単変量解析 : codeulcer_fit <- survfit(Surv(time, cens) ~ ulcer, data = df1) ulcer_p <- ggsurvplot(fit = ulcer_fit, risk.table = TRUE, pval = TRUE, conf.int = TRUE)ulcer_p

単変量解析 : result

多変量解析 : Cox hazard model

• 各時刻において、ある共変量が 1 増加したときにイベント発生リスク(ハザード比)が何倍になるかを推定• 時間に依らずハザード比が一定である仮定→  残差分析(省略)

多変量解析 : code## multivariatecox_fit <- coxph(Surv(time, cens) ~ sex + age + thickness + ulcer, data = df1)## variable selectioncox_fit2 <- stepAIC(cox_fit)summary(cox_fit2)

多変量解析 : result> summary(cox_fit2, digits = 3)Call:coxph(formula = Surv(time, cens) ~ sex + age + thickness + ulcer, data = df1)

n= 191, number of events= 57

coef exp(coef) se(coef) z Pr(>|z|) sex 0.45794 1.58082 0.26832 1.707 0.087873 . age 0.01429 1.01439 0.00834 1.713 0.086634 . thickness 0.11137 1.11781 0.03725 2.990 0.002790 ** ulcer1 1.13193 3.10162 0.30961 3.656 0.000256 ***

多変量解析 : result> summary(cox_fit2, digits = 3)Call:coxph(formula = Surv(time, cens) ~ sex + age + thickness + ulcer, data = df1)

n= 191, number of events= 57

coef exp(coef) se(coef) z Pr(>|z|) sex 0.45794 1.58082 0.26832 1.707 0.087873 . age 0.01429 1.01439 0.00834 1.713 0.086634 . thickness 0.11137 1.11781 0.03725 2.990 0.002790 ** ulcer1 1.13193 3.10162 0.30961 3.656 0.000256 ***

結局、 thickness の予測能は?

結局、 thickness の予測能は?> range(df1$thickness)[1] 0.10 17.42

p <- ggplot(data = df1, aes(x = thickness)) + geom_histogram(binwidth = 1.0)p <- p + ggtitle("histgram of thickness by 1.0 mm")p <- p + theme_bw()p

結局、 thickness の予測能は?> range(df1$thickness)[1] 0.10 17.42

p <- ggplot(data = df1, aes(x = thickness)) + geom_histogram(binwidth = 1.0)p <- p + ggtitle("histgram of thickness by 1.0 mm")p <- p + theme_bw()p

ROC curve について 1値 正しい分類

16 T15 T14 F13 T12 T11 T10 F

9 T8 T8 T8 T8 F7 F6 T5 F

例えば、 11 以上を陽性とした場合、真に T 真に F

陽性 5 1

陰性 5 4

奥村 晴彦 先生の hp より

感度  =  真に T のうち、陽性だった割合     = 5 / 5+5 = 50%

特異度 = 真に F のうち、陰性だった割合     = 4 / 1+4 = 80%1- 特異度 = 偽陽性 (FP)

この Cut-off 値を変化させて感度、特異度(偽陽性)をプロットしたグラフが ROC 曲線

ROC curve について 2• 一般的な ROC curve を時間依存の関数にしたものを今回使う• 詳細は、Heagerty, P.J., Lumley, T., Pepe, M. S. (2000) Time-dependent ROC Curves for Censored Survival Data and a Diagnostic Marker Biometrics, 56, 337 – 344

ROC curve: code## cutoff of 5 years OScutoff <- 365*5AUC_OS_5y <- survivalROC(Stime = df1$time, status = df1$cens, marker = df1$thickness, predict.time = cutoff, method = "KM")plot(AUC_OS_5y$FP, AUC_OS_5y$TP, type="l", xlim=c(0,1), ylim=c(0,1), xlab=paste( "FP", "\n", "AUC = ",round(AUC_OS_5y$AUC,3)), ylab="TP",main="MM thickness OS, Method = KM \n cutoff = 5 years")abline(0,1)

5 years ROC curve: result

Cut-off 値の決定感度 =1, 特異度=1

最短距離

Cut-off 値の決定 : codeOS_5y_df <- cbind.data.frame(AUC_OS_5y$cut.values, AUC_OS_5y$TP, AUC_OS_5y$FP)colnames(OS_5y_df) <- c("cut_values", "TP", "FP")OS_5y_df <- OS_5y_df %>% dplyr::mutate(distance = ((1-TP)^2 + (FP)^2)) distance <- OS_5y_df %>% dplyr::arrange(distance)round(head(distance), 3)

Cut-off 値の決定 : result> round(head(distance), 3) cut_values TP FP distance Youden_index1 2.26 0.765 0.310 0.151 0.4552 2.34 0.743 0.310 0.162 0.4333 2.10 0.786 0.344 0.164 0.4424 1.94 0.808 0.358 0.165 0.4515 3.22 0.634 0.179 0.166 0.4556 3.06 0.655 0.234 0.173 0.421

Cross validation (4-folds)• ランダムに 4 群に割り付けてset.seed(55)df_sample <- df1 %>% dplyr::mutate(group = sample(x = c(1:4), size = dim(df1)[1], replace = TRUE))

> df_sample$group <- as.factor(df_sample$group)> summary(df_sample$group) 1 2 3 4 44 51 42 54

Cross validation (4-folds): result

Cutoff = 1.94, AUC = 0.736 Cutoff = 2.26, AUC = 0.796

Cutoff = 2.26, AUC = 0.762 Cutoff = 2.26, AUC = 0.797

まとめ• Cut-off 値決めに ROC 曲線が有効• ただし cross-validation で閾値が変動する可能性あり• 生存曲線でも ROC 曲線が使える。パッケージもある

反省• 生存時間の変化によって AUC の変化を示すことができなかった• あくまで ROC 曲線は単変量解析のため、多変量のときの予測性能を保障できない• 次回は自分でデータスクレイピングしたい

反省• 生存時間の変化によって AUC の変化を示すことができなかった→   iAnalysis ~おとうさんの解析日記~ [R program] 時間依存性 ROC 曲線法• あくまで ROC 曲線は単変量解析のため、多変量のときの予測性能を保障できない→Nomogram (Tokyo.R #46 Cox 比例ハザードモデルとその周辺 )→Nomograms for High-Dimensional Data などで正則化• 次回は自分でデータスクレイピングしたい

参考資料• Tokyo R の過去の資料• R によるデータサイエンス 金 明哲• Qiita dplyr を使いこなす!• 大阪大学大学院医学系研究科 老年・腎臓内科学 腎臓内科 hp• R bloggers “Survival plots have never been so informative”

Enjoy !

ROC curve: codedf_1 <- df_sample %>%

dplyr::filter(!(group == 1))

## cutoff of 5 years OS

cutoff <- 365*5

AUC_OS_5y <- survivalROC(Stime = df_1$time, status = df_1$cens, marker = df_1$thickness, predict.time = cutoff, method = "KM")

OS_5y_df <- cbind.data.frame(AUC_OS_5y$cut.values, AUC_OS_5y$TP, AUC_OS_5y$FP)

colnames(OS_5y_df) <- c("cut_values", "TP", "FP")

OS_5y_df <- OS_5y_df %>%

dplyr::mutate(distance = ((1-TP)^2 + (FP)^2)) %>%

dplyr::mutate(Youden_index = (TP - FP))

distance <- OS_5y_df %>%

dplyr::arrange(distance)

cut_value <- distance[1, 1]

cut_value

df_cut <- df_sample %>%

dplyr::filter(group == 1) %>%

dplyr::mutate(thick_dicot = ifelse(thickness >= cut_value, 1, 0))

## univariate by thickness

## low:0, high:1

thick_fit <- survfit(Surv(time, cens) ~ thick_dicot, data = df_cut)

thick_fit

thick_p <- ggsurvplot(fit = thick_fit,

risk.table = TRUE,

pval = TRUE,

conf.int = TRUE)

thick_p

top related