tests/testthat/test-confusion.R

test_that("confmatr_by_threshold calculates all metrics correctly", {
  test_vec <- c(0.8, 0.7, 0.6, 0.3, 0.4, 0.2)
  true_vec <- c(1L, 1L, 0L, 0L, 1L, 0L)
  res <- confmatr_by_threshold(test_vec, true_vec, threshold = 0.5, pos_val = 1)

  expect_equal(res$threshold, 0.5)                     # evaluated at cutoff 0.5
  expect_equal(res$P, 3)                                # three positives in truth vector
  expect_equal(res$N, 3)                                # three negatives in truth vector
  expect_equal(res$TP, 2)                               # two positives above threshold
  expect_equal(res$FN, 1)                               # one positive below threshold
  expect_equal(res$FP, 1)                               # one negative above threshold
  expect_equal(res$TN, 2)                               # two negatives below threshold
  expect_equal(res$TPR, 2/3)                            # TP / P
  expect_equal(res$SEN, 2/3)                            # alias for TPR
  expect_equal(res$FNR, 1/3)                            # 1 - TPR
  expect_equal(res$FPR, 1/3)                            # FP / N
  expect_equal(res$TNR, 2/3)                            # 1 - FPR
  expect_equal(res$SPC, 2/3)                            # alias for TNR
  expect_equal(res$BM, 1/3)                             # TPR + TNR - 1
  expect_equal(res$PT, sqrt(2) - 1)                     # probability threshold formula
  expect_equal(res$Prevalence, 0.5)                     # P / (P + N)
  expect_equal(res$PPV, 2/3)                            # TP / (TP + FP)
  expect_equal(res$NPV, 2/3)                            # TN / (TN + FN)
  expect_equal(res$LRp, 2)                              # TPR / FPR
  expect_equal(res$LRn, 1/2)                            # FNR / TNR
  expect_equal(res$ACC, 4/6)                            # (TP + TN) / (P + N)
  expect_equal(res$FDR, 1/3)                            # 1 - PPV
  expect_equal(res$FOR, 1/3)                            # 1 - NPV
  expect_equal(res$MK, 1/3)                             # PPV + NPV - 1
  expect_equal(res$deltaP, 1/3)                         # deltaP equals markedness
  expect_equal(res$DOR, 4)                              # LRp / LRn
  expect_equal(res$BA, 2/3)                             # (TPR + TNR) / 2
  expect_equal(res$F_1, 2/3)                            # 2 * PPV * TPR / (PPV + TPR)
  expect_equal(res$FM, 2/3)                             # sqrt(PPV * TPR)
  expect_equal(res$MCC, 1/3)                            # Matthews correlation coefficient
  expect_equal(res$TS, 1/2)                             # TP / (TP + FN + FP)
  expect_equal(res$CSI, 1/2)                            # critical success index
})

test_that("confmatr_by_threshold handles multiple thresholds and options", {
  test_vec <- c(0.8, 0.7, 0.6, 0.3, 0.4, 0.2)
  true_vec <- c(1L, 1L, 0L, 0L, 1L, 0L)

  res <- confmatr_by_threshold(test_vec, true_vec, threshold = c(0.5, 0.7), pos_val = 1)
  expect_equal(nrow(res), 2)                             # vector thresholds return one row per cutoff

  res_high <- res[res$threshold == 0.7, ]
  expect_equal(res_high$TP, 2)                           # two positives exceed 0.7
  expect_equal(res_high$FP, 0)                           # no negatives exceed 0.7
  expect_equal(res_high$FPR, 0)                          # FP / N = 0
  expect_equal(res_high$TNR, 1)                          # all negatives correctly classified
  expect_equal(res_high$PPV, 1)                          # TP / (TP + FP) with FP=0
  expect_equal(res_high$NPV, 3/4)                        # TN / (TN + FN)
  expect_equal(res_high$LRp, Inf)                        # division by zero when FPR = 0
  expect_equal(res_high$LRn, 1/3)                        # FNR / TNR
  expect_equal(res_high$BA, 5/6)                         # (TPR + TNR) / 2
  expect_equal(res_high$F_1, 4/5)                        # 2 * PPV * TPR / (PPV + TPR)
  expect_equal(res_high$FM, sqrt(2/3))                   # sqrt(PPV * TPR)
  expect_equal(res_high$MCC, sqrt(1/2))                  # simplified with zero FPR
  expect_equal(res_high$TS, 2/3)                         # TP / (TP + FN + FP)
  expect_equal(res_high$CSI, 2/3)                        # critical success index

  res_pref <- confmatr_by_threshold(test_vec, true_vec, threshold = c(0.5, 0.7), pos_val = 1, prepend = "x_")
  expect_true(all(startsWith(names(res_pref), "x_")))    # prefix applied to all columns

  res_cols <- confmatr_by_threshold(test_vec, true_vec, threshold = 0.5, pos_val = 1, cols = c(threshold, TPR, FPR))
  expect_equal(names(res_cols), c("threshold", "TPR", "FPR")) # only selected columns returned
})

Try the xpose.xtras package in your browser

Any scripts or data that you put into this service are public.

xpose.xtras documentation built on April 22, 2026, 1:09 a.m.