【R语言】校准曲线,绘制原理


①获取predict的结果,"prob.Case"这一列就是预测风险概率,"truth"列为实际发生结局的分组

②将prob.Case进行分桶(简单理解为分组,一般分10组),常见的分桶方式有两种:一是将prob.Case从大到小排序后,按照样本数平均分为10组,每组样本数相等

③计算10个分桶中prob.Case的桶内均值作为预测概率;

④计算10个分桶中实际患病者(truth = 1 | truth=Case)占该桶样本数的频率作为实际概率;

⑤将10对预测概率和实际概率分别作为横坐标值和纵坐标值得到10个散点;

⑥将这些点连起来,即为校准曲线中的Apparent线。

R包的函数

r 复制代码
function (df, outcome, positive, prediction, model, n_bins = 10, 
  show_loess = FALSE, plot_title = "", ...) 
{
  if ((n_bins > 0 && show_loess == TRUE) || (n_bins == 0 && 
    show_loess == FALSE)) {
    stop("You must either set n_bins > 0 and show_loess to FALSE or set n_bins to 0 and show_loess to TRUE. Both cannot be displayed.")
  }
  how_many_models = df[[model]] %>% unique() %>% length()
  df[[outcome]] = ifelse(positive == df[[outcome]], 1, 0)
  if (n_bins > 0) {
    df <- df %>% dplyr::group_by(!!rlang::parse_expr(model)) %>% 
      dplyr::mutate(bin = dplyr::ntile(!!rlang::parse_expr(prediction), 
        n_bins)) %>% dplyr::group_by(!!rlang::parse_expr(model), 
      bin) %>% dplyr::mutate(n = dplyr::n(), bin_pred = mean(!!rlang::parse_expr(prediction), 
      na.rm = TRUE), bin_prob = mean(as.numeric(as.character(!!rlang::parse_expr(outcome))), 
      na.rm = TRUE), se = sqrt((bin_prob * (1 - bin_prob))/n), 
      ul = bin_prob + 1.96 * se, ll = bin_prob - 1.96 * 
        se) %>% dplyr::mutate_at(dplyr::vars(ul, ll), 
      . %>% scales::oob_squish(range = c(0, 1))) %>% dplyr::ungroup()
  }
  g1 = ggplot2::ggplot(df) + ggplot2::scale_y_continuous(limits = c(0, 
    1), breaks = seq(0, 1, by = 0.1)) + ggplot2::scale_x_continuous(limits = c(0, 
    1), breaks = seq(0, 1, by = 0.1)) + ggplot2::geom_abline(linetype = "dashed")
  if (show_loess == TRUE) {
    g1 = g1 + ggplot2::stat_smooth(ggplot2::aes(x = !!rlang::parse_expr(prediction), 
      y = as.numeric(!!rlang::parse_expr(outcome)), color = !!rlang::parse_expr(model), 
      fill = !!rlang::parse_expr(model)), se = TRUE, method = "loess")
  }
  else {
    g1 = g1 + ggplot2::aes(x = bin_pred, y = bin_prob, color = !!rlang::parse_expr(model), 
      fill = !!rlang::parse_expr(model)) + ggplot2::geom_ribbon(ggplot2::aes(ymin = ll, 
      ymax = ul, ), alpha = 1/how_many_models) + ggplot2::geom_point(size = 2) + 
      ggplot2::geom_line(size = 1, alpha = 1/how_many_models)
  }
  g1 = g1 + ggplot2::xlab("Predicted Probability") + ggplot2::ylab("Observed Risk") + 
    ggplot2::scale_color_brewer(name = "Models", palette = "Set1") + 
    ggplot2::scale_fill_brewer(name = "Models", palette = "Set1") + 
    ggplot2::theme_minimal() + ggplot2::theme(aspect.ratio = 1) + 
    ggplot2::ggtitle(plot_title)
  g2 <- ggplot2::ggplot(df, ggplot2::aes(x = !!rlang::parse_expr(prediction))) + 
    ggplot2::geom_density(alpha = 1/how_many_models, ggplot2::aes(fill = !!rlang::parse_expr(model), 
      color = !!rlang::parse_expr(model))) + ggplot2::scale_x_continuous(limits = c(0, 
    1), breaks = seq(0, 1, by = 0.1)) + ggplot2::coord_fixed() + 
    ggplot2::xlab("") + ggplot2::ylab("") + ggplot2::scale_color_brewer(palette = "Set1") + 
    ggplot2::scale_fill_brewer(palette = "Set1") + ggplot2::theme_minimal() + 
    ggeasy::easy_remove_y_axis() + ggeasy::easy_remove_legend(fill, 
    color) + ggplot2::theme_void() + ggplot2::theme(aspect.ratio = 0.1)
  layout = c(patchwork::area(t = 1, b = 10, l = 1, r = 10), 
    patchwork::area(t = 11, b = 12, l = 1, r = 10))
  g1/g2
}

自己写的函数

r 复制代码
# 读取数据
data <- prediction_all_rf

get_cal <- function(data=prediction_all_rf){
  data <- data %>% mutate(bucket = ntile(prob.Case, 10))
  bucket_means <- data %>% group_by(bucket) %>% 
    summarise(predicted_prob = mean(prob.Case))
  actual_probs <- data %>% group_by(bucket) %>% 
    summarise(actual_prob = mean(truth == "Case"))
  calibration_data <- left_join(bucket_means, actual_probs, by = "bucket")
  calibration_data$type=data$type[1]
  return(calibration_data)
}

cal_rf <- get_cal(data = prediction_all_rf)
cal_kkmm <- get_cal(data = prediction_all_kknn)
cal_SVM <- get_cal(data = prediction_all_SVM)
cal_xgb <- get_cal(data = prediction_all_xgb)

calibration_data <- rbind(cal_rf,cal_kkmm,cal_SVM,cal_xgb)
# ⑥ 将这些点连起来,即为校准曲线中的Apparent线
ggplot(calibration_data, 
       aes(x = predicted_prob, y = actual_prob,group = type,colour = type)) +
  geom_point() +
  geom_line() +
  labs(title = "Calibration Curve", x = "Predicted Probability", y = "Actual Probability") +
  theme_minimal()+
  ggplot2::scale_y_continuous(limits = c(0, 
                                           1), breaks = seq(0, 1, by = 0.1)) + ggplot2::scale_x_continuous(limits = c(0, 
                                                                                                                      1), breaks = seq(0, 1, by = 0.1)) + ggplot2::geom_abline(linetype = "dashed")
相关推荐
czhc11400756632 天前
LINUX913 shell:set ip [lindex $argv 0],\r,send_user,spawn ssh root@ip “cat “
tcp/ip·r语言·ssh
zhangfeng11332 天前
win7 R 4.4.0和RStudio1.25的版本兼容性以及系统区域设置有关 导致Plots绘图面板被禁用,但是单独页面显示
开发语言·人工智能·r语言·生物信息
zhangfeng11332 天前
在 R 语言里,`$` 只有一个作用 按名字提取“列表型”对象里的单个元素 对象 $ 名字
开发语言·windows·r语言
高-老师2 天前
R语言生物群落(生态)数据统计分析与绘图实践技术应用
开发语言·r语言·生物群落
WangYan20223 天前
R语言:数据读取与重构、试验设计(RCB/BIB/正交/析因)、ggplot2高级绘图与统计检验(t检验/方差分析/PCA/聚类)
r语言·ggplot2·dplyr
zhangfeng11333 天前
错误于make.names(vnames, unique = TRUE): invalid multibyte string 9 使用 R 语言进行数据处理时
开发语言·r语言·生物信息
zhangfeng11333 天前
R geo 然后读取数据的时候 make.names(vnames, unique = TRUE): invalid multibyte string 9
开发语言·chrome·r语言·生物信息
梦想的初衷~4 天前
R语言生物群落数据分析全流程:从数据清洗到混合模型与结构方程
机器学习·r语言·生态·环境
没有梦想的咸鱼185-1037-16636 天前
基于R语言机器学习方法在生态经济学领域中的实践技术应用
开发语言·机器学习·数据分析·r语言
zhangfeng11337 天前
R 语法高亮为什么没有,是需要安装专用的编辑软件,R语言自带的R-gui 功能还是比较简单
开发语言·r语言