# 评价已取得的二分类评分；huyiba_rawdata_validation 每行有真实结局与对应分数。
outcome_var <- "outcome"
score_var <- "score"
positive_level <- "yes"
negative_level <- "no"
# 评分必须越高越倾向阳性；若评分定义相反，按来源预先调整方向。

# 不丢弃行：分数与真实结局须来自同一批评价记录，并已逐行对齐。
input_columns <- c(outcome_var, score_var)
if (anyDuplicated(input_columns) || !all(input_columns %in% names(huyiba_rawdata_validation))) {
  stop("真实结局列和评分列必须存在且不同。")
}
huyiba_analysis_data <- huyiba_rawdata_validation[input_columns]
outcomes <- as.character(huyiba_analysis_data[[outcome_var]])
scores <- huyiba_analysis_data[[score_var]]
if (anyNA(outcomes) || identical(positive_level, negative_level) ||
    !setequal(outcomes, c(negative_level, positive_level)) ||
    !is.numeric(scores) || !is.null(dim(scores)) || any(!is.finite(scores))) {
  stop("评价数据须同时含两个指定类别，且每行有一个有限数值评分。")
}

# 从高分向低分扫过阈值；同分记录一起进入，判阳性规则为 score >= threshold。
score_order <- order(scores, decreasing = TRUE)
sorted_scores <- scores[score_order]
positive <- outcomes[score_order] == positive_level
last_at_score <- !duplicated(sorted_scores, fromLast = TRUE)
curve <- data.frame(
  threshold = c(Inf, sorted_scores[last_at_score]),
  false_positive_rate = c(0, cumsum(!positive)[last_at_score] / sum(!positive)),
  sensitivity = c(0, cumsum(positive)[last_at_score] / sum(positive))
)

# 在假阳性率尺度上做梯形积分；同分的阳性/阴性配对各计半次。
left <- seq_len(nrow(curve) - 1L)
auc <- sum(diff(curve$false_positive_rate) *
  (curve$sensitivity[left] + curve$sensitivity[left + 1L]) / 2)
huyiba_result <- list(
  n = length(scores), positive_n = sum(positive), auc = auc, curve = curve
)
print(c(n = huyiba_result$n, positive = huyiba_result$positive_n, AUC = auc))

graphics::plot(
  curve$false_positive_rate, curve$sensitivity, type = "l",
  xlim = c(0, 1), ylim = c(0, 1), las = 1,
  xlab = "False positive rate (1 - specificity)", ylab = "Sensitivity",
  col = "#176181", lwd = 2
)
graphics::segments(0, 0, 1, 1, lty = 2, col = "gray55", lwd = 1.4)
