数据分析:多诊断指标ROC分析

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者!

image.png

数据分析:多诊断指标ROC分析

介绍

pROC::roc函数能够使用一个指标(predictor)去区分两个或多个分组(response),并计算95%置信区间的原理基于以下几个关键点:

  1. ROC曲线:ROC曲线是一种图形表示,用于展示分类模型在所有可能的分类阈值下的性能。它通过绘制真正类率(True Positive Rate, TPR)和假正类率(False Positive Rate, FPR)来评估模型的分类能力。
  2. AUC:曲线下面积(Area Under the Curve, AUC)是一个单一的数字,用于描述ROC曲线下的面积。AUC的值介于0和1之间,其中1表示完美的分类器,0.5表示没有区分能力的分类器(相当于随机猜测)。
  3. 指标转换pROC::roc函数首先将分组变量(response)中的类别标签转换为二进制形式(例如,"healthy"和"cancer"转换为0和1)。这样,可以使用逻辑回归或其他分类方法来估计预测指标(predictor)的概率。
  4. 排序和阈值pROC::roc函数根据预测指标的概率对样本进行排序,并计算在每个可能的阈值下模型的TPR和FPR。
  5. 置信区间pROC::roc函数计算AUC的95%置信区间,这是通过使用非参数方法(如自助法)或正态近似方法来实现的。ci = TRUE参数指示函数计算这个置信区间。
  6. 模型拟合:在内部,pROC::roc可能使用逻辑回归模型来拟合数据,将预测指标作为预测变量,将分组变量作为响应变量。
  7. 水平设置levels参数指定了响应变量的类别顺序。这很重要,因为ROC曲线是基于类别的正负性来绘制的。在逻辑回归中,通常将较高级别的类别设置为“成功”或“事件”。
  8. 统计测试pROC::roc函数还包括对AUC是否统计显著不同于0.5(即随机猜测)的测试,这可以通过pROC::summary.roc函数获得。

通过这些步骤,pROC::roc函数提供了一种评估和比较不同预测指标或模型在区分两个或多个分组方面性能的方法。这种方法在医学研究、生物统计学和其他领域中非常常用,尤其是在诊断测试评估和风险预测模型的开发中。

加载R包

knitr::opts_chunk$set(warning = F, message = F)

library(tidyverse)
library(pROC)
library(ggrepel)

导入数据

数据可从以下链接下载(画图所需要的所有数据):数据分析:多诊断指标ROC分析

data <- read.csv("./inputdata/54-All_Scores.csv", row.names = 1)

head(data)
sample type score.meth score.delfi score.meth_reg ens_preds
PGDX16571P healthy 0.1147934 0.2261810 0.08935560 0.06348261
PGDX16601P cancer 0.5178563 0.9582597 0.41919691 0.84425808
PGDX16605P cancer 0.9422967 0.9996974 0.91752178 0.98553102
PGDX17725P cancer 0.9174640 0.9819394 0.69399546 0.95644096
PGDX17735P cancer 0.6345916 0.9403198 0.06706129 0.48634758
PGDX17740P cancer 0.9886795 0.9987350 0.99318466 0.98982497

数据预处理

根据score等指标分别计算它们区分healthy和cancer的能力。这段R代码定义了一个名为get_ROC_CI的函数,用于计算并汇总不同数据集的ROC曲线分析结果,并最终将结果整合到同一个图形上展示。下面是代码的详细解释:数据分析:多诊断指标ROC分析

1-10. get_ROC_CI函数接受五个参数:

  • inputdata:输入的数据框,包含用于计算ROC曲线的数据。
  • index:用于预测的指标列的名称。
  • group:包含响应变量(如“健康”或“癌症”)的分组列的名称。
  • group_names:一个向量,包含group列中的所有可能的组名。
  • tag:一个字符串,用于标记结果的类型(如DELFI、Methylation或Ensemble)。

12-13. 将inputdata中相应的列名替换为"Idx"和"Cmp",以便与pROC::roc函数的要求一致。

15-21. 使用pROC::roc函数计算ROC曲线。response参数设置为分组变量,predictor设置为预测得分,ci = TRUE表示需要计算95%置信区间,levels参数指定了分组变量的顺序。

23-26. 使用pROC::coords函数和Youden指数确定最佳阈值,这将用于最大化真正例和真负例的总和。

28-33. 再次使用pROC::coords函数,根据最佳阈值获取最佳性能指标,如敏感性、特异性等。

35-39. 将AUC和95%置信区间格式化为一个字符串,包含标签、AUC值和CI的上下限。

41-47. 创建一个新的数据框(tibble),包含ROC曲线的类型(带有标签的AUC和CI)、敏感性(sensitivities)和特异性(specificities)。返回一个列表,包含ROC对象、最佳阈值、最佳性能指标和ROC数据框。

51-55. 分别对三个不同的数据集(Methylation、DELFI、Ensemble)调用get_ROC_CI函数,并将结果存储在相应的变量中。

57-65. 将三个结果的数据框合并,并使用dplyr::mutatefactor函数调整type列,以确保所有的类型按照相同的顺序排列。这有助于后续在同一图形上统一展示。

get_ROC_CI <- function(
  inputdata,
  index,
  group,  
  group_names,
  tag) {
  
  # inputdata = data
  # index = "score.delfi"
  # group = "type"
  # group_names = c("healthy", "cancer")
  # tag = "DELFI"  
  
  colnames(inputdata)[which(colnames(inputdata) == index)] <- "Idx"
  colnames(inputdata)[which(colnames(inputdata) == group)] <- "Cmp"
  
  # ROC
  roc_res <- pROC::roc(
    response = inputdata$Cmp, 
    predictor = inputdata$Idx, 
    ci = TRUE, 
    levels = c("healthy", "cancer"))
  
  # 95% CI
  roc_CI <- paste0(tag, ": ", round(roc_res$auc[1], 2), 
                   " (", round(roc_res$ci[1], 2), "-", 
                   round(roc_res$ci[3], 2), ")")
  
  # ROC data.frame
  roc_df <- tibble(
    type = roc_CI, 
    sens = roc_res$sensitivities, 
    spec = roc_res$specificities)
  
  res <- list(roc = roc_res,
              cutoff = best_threshold,
              best = best_performance,
              df = roc_df)
  
  return(res)
}

Methylation_res <- get_ROC_CI(
  inputdata = data,
  index = "score.meth_reg",
  group = "type",
  group_names = c("healthy", "cancer"),
  tag = "Methylation") 

DELFI_res <- get_ROC_CI(
  inputdata = data,
  index = "score.delfi",
  group = "type",
  group_names = c("healthy", "cancer"),
  tag = "DELFI")

Ensemble_res <- get_ROC_CI(
  inputdata = data,
  index = "ens_preds",
  group = "type",
  group_names = c("healthy", "cancer"),
  tag = "Ensemble") 

merge_res <- rbind(Methylation_res$df, DELFI_res$df, Ensemble_res$df) %>%
  dplyr::mutate(type = factor(type, levels = c(unique(Methylation_res$df$type),
                                               unique(DELFI_res$df$type),
                                               unique(Ensemble_res$df$type))))

head(merge_res)
type sens spec
DELFI: 0.89 (0.84-0.94) 1 0.000000000
DELFI: 0.89 (0.84-0.94) 1 0.004761905
DELFI: 0.89 (0.84-0.94) 1 0.009523810
DELFI: 0.89 (0.84-0.94) 1 0.014285714
DELFI: 0.89 (0.84-0.94) 1 0.019047619
DELFI: 0.89 (0.84-0.94) 1 0.023809524

ROC 曲线图

数据分析:多诊断指标ROC分析

image.png

结果:三种指标对分组Healthy和Cancer的区分ROC曲线。合并后的指标能更有效区分Healthy和Cancer(AUC = 0.93)。

上述三个指标对应的区分Healthy和Cancer的阈值

print(paste("Cutoff of Methylation is", round(as.numeric(Methylation_res$cutoff), 4), " (>:Cancer; <=: Healthy)"))

print(paste("Cutoff of DELFI is", round(as.numeric(DELFI_res$cutoff), 4), " (>:Cancer; <=: Healthy)"))

print(paste("Cutoff of Ensemble is", round(as.numeric(Ensemble_res$cutoff), 4), " (>:Cancer; <=: Healthy)"))
[1] "Cutoff of Methylation is 0.2982  (>:Cancer; <=: Healthy)"
[1] "Cutoff of DELFI is 0.3298  (>:Cancer; <=: Healthy)"
[1] "Cutoff of Ensemble is 0.2289  (>:Cancer; <=: Healthy)"

总结

通过应用pROC::roc函数,我们对预测指标(predictor)进行了效能分析,旨在评估其区分两个不同分组(response)的能力。通过计算得到的AUC值,我们量化了模型的整体分类性能。进一步地,利用Youden指数,我们确定了最优的区分阈值,以实现在灵敏度和特异性之间最佳平衡。

最终,为了综合比较不同指标的分类效能,我们将它们的ROC曲线汇总在单一图形上进行了展示,直观地呈现了每个指标的AUC值和最优阈值。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容