Open-source agentic AI for transaction monitoring. Just ask Jooby.What's Jube? →

Categorical and survival tool catalogue

Jube.Service/Agent/AdvancedAnalyticsTools/CategoricalAndSurvival/ is one of the ten semantic tool groups an AskJooby agent calls directly by name. None of its 70 tools has any entry elsewhere under docs/, which means Jadek, the reply-validating agent, can never confirm a claim that cites one: a correct answer built on, say, ComputeRocCurve or FitCoxProportionalHazards fails validation purely because nothing else in the RAG-indexed corpus says what that tool computes. This page covers the whole group, tool by tool, grouped by the source file each tool lives in. Every tool is bound to the group name CategoricalAndSurvival and gated behind the Analytics permission; none of them persist anything, and none of them train or save a model.

A handful of conventions recur across almost every tool in this group and are stated once here rather than in each entry: a binary outcome is always encoded as 1 for the event of interest and 0 otherwise, and a row whose score or time is NaN is silently dropped and counted in the result’s SkippedRows field rather than rejected outright, unlike most other malformed input (wrong lengths, negative counts, out-of-range confidence levels), which throws. Tools that need both outcome classes present (anything built on a ROC curve, a threshold sweep or a confusion matrix) reject data where every usable row is the same class. Confidence levels are a fraction strictly between 0 and 1, defaulting to 0.95, and intervals built from a normal approximation use the corresponding two-sided z value.

Confusion-matrix and classification metrics (ConfusionMatrixTools)

These five tools all return the same rich ConfusionMetricsResult, or the multi-class analogue, built around the confusion matrix at one fixed operating point. The binary result carries accuracy, precision (positive predictive value), recall (sensitivity, detection rate), specificity, negative predictive value, false positive and negative rates, false discovery and omission rates, F1 and a general F-beta, Matthews correlation, Cohen’s kappa, balanced accuracy, Youden’s J, markedness, geometric mean, the two likelihood ratios, the diagnostic odds ratio, the predicted positive rate (alert rate) and lift, with Wilson intervals on accuracy, precision, recall and specificity. Precision, recall, specificity, the F-scores, Matthews correlation and kappa report 0 when their denominator is empty rather than NaN, following the shared platform convention; every other ratio is NaN when undefined.

CalculateBinaryClassificationMetricsFromCounts computes this full metric set directly from the four confusion counts (true positives, false positives, true negatives, false negatives) of a rule, alert or model evaluated at one point. beta (default 1) weights the F-beta measure above 1 to favour recall or below 1 to favour precision, and an optional pair costFalseNegative/costFalsePositive, supplied together, adds the expected cost per case to the result. All four counts must be non-negative and not all zero.

CalculateBinaryClassificationMetricsFromLabels reaches the same result from two parallel 0/1 arrays, actual and predicted, by counting the confusion matrix itself first; use it when per-case flags are available rather than pre-aggregated counts.

CalculateBinaryClassificationMetricsAtThreshold turns a continuous score or probability into flags at one threshold (a case is flagged when its score is greater than or equal to it) and evaluates the same metrics against the true 0/1 outcome. Rows with a NaN score are dropped; see ComputeThresholdSweep to inspect many thresholds at once, or the SelectThreshold* tools to choose one automatically.

CalculateMulticlassClassificationMetrics evaluates a multi-class classifier from two parallel arrays of class labels, actual and predicted. It builds the confusion matrix (rows actual, columns predicted) over the distinct labels observed (or an explicit classOrder, capped at 500 classes), then returns overall accuracy with an interval, balanced accuracy, Cohen’s kappa with its standard error and interval (optionally Linear or Quadratic weighted via kappaWeighting for ordered classes), a multi-class Matthews correlation, per-class precision/recall/specificity/F1/ F-beta/support, macro, micro and support-weighted averages, and the topConfusions most frequent off-diagonal confusions. Macro treats every class equally, weighted follows class size, and micro pools all cases and equals accuracy; a class that is never predicted has precision 0, and pairs with a blank label on either side are skipped.

CalculateMulticlassMetricsFromConfusionMatrix computes the identical metric set, but from a square matrix of counts already laid out with rows as actual classes and columns as predicted classes in a shared order, rather than from raw labels; counts must be whole numbers and the matrix no larger than 500 by 500.

Contingency tables and categorical association (ContingencyAssociationTools)

CrossTabulateCategories builds a contingency table (cross-tabulation) from two parallel arrays of category labels, one pair per row, returning the sorted row and column labels, the count in every cell, both sets of margins (RowTotals/ColumnTotals), the grand total and the number of pairs skipped because either label was blank. It is the normal way to turn two raw categorical columns into the count table the association tools below expect.

AnalyseContingencyTableAssociation tests and measures association between two categorical variables from an existing table of counts (at least 2 by 2). It returns Pearson’s chi-square with its degrees of freedom and p-value, a likelihood-ratio G statistic, a Yates continuity-corrected chi-square for 2-by-2 tables, the expected counts under independence, the Pearson and adjusted standardised residuals (a cell with an absolute adjusted residual above about 2 is driving the association), the cell-level chi-square contributions, and the effect sizes Cramér’s V, bias-corrected Cramér’s V, phi, the contingency coefficient and Tschuprow’s T, plus a plain-language EffectSizeLabel. Warnings reports when expected counts are too small for the chi-square approximation to be trusted (SmallestExpectedCount and FractionOfCellsExpectedBelowFive are both returned so the caller can judge for itself); a row or column with zero observations is rejected outright.

AnalyseCategoricalAssociationFromLabels is the same analysis starting from two parallel label arrays rather than a prepared table: it calls CrossTabulateCategories internally and then runs the full association analysis on the result, dropping any case with a blank label on either side. The adjusted residuals are the place to look for which specific category pairs occur more or less often than independence predicts.

CalculateGoodmanKruskalLambda computes Goodman and Kruskal’s lambda from a count table: the proportional reduction in prediction error for one variable when the other is known. LambdaColumnGivenRow is the improvement in guessing the column category from the row category, LambdaRowGivenColumn the reverse, and LambdaSymmetric their average; 0 means no help, 1 means perfect prediction from the other variable. Lambda can be 0 even when a real association exists, because it only credits a change to the most common category, and it is NaN when the predicted variable is already concentrated in a single category.

CalculateOrdinalAssociationMeasures measures the strength and direction of association between two variables whose rows and columns are already in a meaningful increasing order (not just arbitrary categories). It returns concordant, discordant and tied-pair counts, Goodman-Kruskal gamma with its asymptotic standard error and confidence interval, Kendall’s tau-b, Stuart’s tau-c and Somers’ D in both directions and symmetric, each running from -1 (perfectly reversed order) through 0 to +1. Gamma ignores ties and is therefore the largest in magnitude of the group; tau-b and Somers’ D penalise ties. The table is capped at 10,000 cells, and supplying rows or columns out of their natural order makes the sign and size of every statistic meaningless.

CalculateCategoricalMutualInformation quantifies dependence between two categorical variables with information theory rather than a chi-square assumption of order or shape. It returns the entropy of each variable, their joint entropy, the mutual information (how much knowing one variable reduces uncertainty about the other, 0 under independence), a version normalised to between 0 and 1, and Theil’s uncertainty coefficients in each direction and symmetric. useBits (default true) reports in bits rather than natural units (nats). A variable with a single category has zero entropy and gives NaN coefficients.

RankCategoricalColumnsByAssociationWithOutcome screens many categorical columns at once against a shared binary outcome and ranks them from strongest to weakest. For every named column it cross-tabulates the categories against the outcome and returns the chi-square test with its p-value and a Benjamini-Hochberg adjusted p-value (controlling false discoveries across the many columns tested at once), Cramér’s V and its bias-corrected form, the information value (weight-of-evidence separation, as in CalculateInformationValueByCategory) and the mutual information in bits. Results are ordered by CramersVBiasCorrected descending; a column that is constant, or an outcome with a single class among the usable rows, gets NaN statistics and an explanatory Note rather than being dropped from the output. Blank category values are skipped per column, independently of other columns.

Odds, risk and 2-by-2 table analysis (OddsAndRiskTools)

Nine of this file’s ten tools work from a 2-by-2 table laid out as exposed-events, exposed-non-events, unexposed-events, unexposed-non-events; several share an applyZeroCellCorrection flag that adds 0.5 to every cell when any cell is zero (the Haldane-Anscombe correction) so a ratio stays finite rather than exploding to infinity or collapsing to zero.

CalculateOddsRatio computes the odds ratio comparing an exposed group with an unexposed group: (exposed events times unexposed non-events) divided by (exposed non-events times unexposed events). Above 1 means the event is more likely in the exposed group; an interval containing 1 means no clear difference. The interval, z statistic and two-sided p-value use the Woolf logit method; for rare events the odds ratio approximates the risk ratio below.

CalculateRiskRatio computes the risk ratio (relative risk): the exposed event rate divided by the unexposed event rate, with a log-scale interval, z statistic and p-value. RelativeRiskReduction is one minus the ratio. If either group has no events and the correction is enabled, 0.5 is added to every cell so the ratio and interval stay finite.

CalculateRiskDifference computes the absolute risk difference (exposed rate minus unexposed rate) with a Wald interval and a Newcombe-Wilson interval that behaves better for rare events, a pooled z test, and the two attributable fractions: AttributableFractionAmongExposed (the share of the exposed group’s own events attributable to exposure) and PopulationAttributableFraction (the share of all events attributable to exposure), both assuming the exposure is causal and the sample mix represents the population.

CalculateNumberNeededToTreat converts a risk difference into the number of exposed cases that must be handled to see one extra event (if the difference is positive, “number needed to harm”) or to prevent one event (if negative, “number needed to treat”), using the reciprocal of the absolute risk difference and the Newcombe interval on the difference for its own bounds. When that interval spans zero the number needed is unbounded above: IntervalSpansInfinity is true and Lower/Upper are NaN; an exact-zero difference also gives NaN, since no finite number of cases produces an extra event.

CalculateYuleAssociation computes Yule’s Q and Yule’s Y for a 2-by-2 table, plus phi and the odds ratio for context. Q equals (ad - bc) / (ad + bc) and runs from -1 to +1, reaching ±1 whenever one off-diagonal cell is empty; Y (the coefficient of colligation) is a gentler version of the same idea. Cells are read as exposed-events (a), exposed-non-events (b), unexposed-events (c), unexposed-non-events (d); a coefficient is NaN when undefined for the zeros supplied.

CalculateDiagnosticLikelihoodRatios computes sensitivity, specificity, the predictive values and both likelihood ratios of a binary rule or alert from its confusion counts, each with a log-scale interval, plus the diagnostic odds ratio. The positive likelihood ratio (sensitivity over one minus specificity) says how much a flag multiplies the odds of the event; the negative likelihood ratio says how much a non-flag multiplies them, with values well below 1 being reassuring. PostTestProbabilityAfterPositive/AfterNegative apply Bayes’ rule at an optional pretestProbability you supply, or at the sample prevalence when left empty; zero cells can make an interval infinite or NaN.

AnalyseTwoByTwoTable runs every standard analysis of a 2-by-2 table in one call: the odds ratio, risk ratio, risk difference (with both Wald and Newcombe intervals), Yule’s Q and Y, phi, Pearson chi-square and a Yates-corrected chi-square with p-values, and the smallest expected count. It is meant as the first look at whether a segment, rule or channel is associated with an outcome; the description itself recommends falling back to an exact test from the hypothesis-testing tool layer when the smallest expected count is below 5.

AnalyseBinaryExposureAndOutcome builds the same 2-by-2 table from two parallel 0/1 columns (an exposure flag and an outcome flag, one entry per case) and runs AnalyseTwoByTwoTable on the result. Exposure 1 means exposed, outcome 1 means the event; any entry that is not 0 or 1 is rejected.

CalculateMantelHaenszelOddsRatio pools several 2-by-2 tables, one per stratum (for example one per country, channel or month), into a single Mantel-Haenszel common odds ratio with a Robins-Breslow-Greenland interval, tested with the Cochran-Mantel-Haenszel chi-square (plain and continuity-corrected). It also runs the Breslow-Day test, with Tarone’s correction, of whether the odds ratio is homogeneous across strata: a small p-value there means the pooled figure should not be quoted alone, because the association genuinely differs by stratum (a Simpson’s-paradox check). Strata with fewer than two usable cases are dropped and counted in StrataDropped; a pooled odds ratio that comes out non-finite (no stratum has both an exposed event and an unexposed non-event, or the reverse) is rejected rather than returned.

CalculateBinomialProportionConfidenceInterval is the one tool in this file that is not a 2-by-2 comparison: it returns a confidence interval for a single proportion (an alert rate, hit rate or fraud rate) from an event count out of a number of trials, with a choice of method — Wilson (the default, reliable near 0 or 1 and at small samples), Clopper-Pearson (exact and conservative), Agresti-Coull, Jeffreys (Bayesian equal-tailed) or Wald (simple but poor for rare events). Zero trials returns NaN for all three fields.

Probability calibration (ProbabilityCalibrationTools)

ComputeCalibrationCurve builds a reliability (calibration) curve for predicted probabilities against a 0/1 outcome: cases are grouped into bins (default 10, up to 1000) either by UniformWidth (splitting 0 to 1 evenly) or EqualCount (similar case counts per bin, which suits skewed rare-event probabilities), and each bin’s mean predicted probability is compared with the event rate actually observed there, with a Wilson interval on the observed rate. Gap is observed minus predicted, so positive means the model under-predicts in that bin; empty bins are omitted entirely. Beyond the per-bin table the result gives the expected calibration error (the count-weighted mean absolute gap), the maximum calibration error, the Brier score, log loss, and a calibration slope and intercept fitted by logistic recalibration on the logit of the probability — slope 1 and intercept 0 are ideal, and a slope below 1 means the model is over-confident. Probabilities must lie between 0 and 1; rows with NaN are dropped.

CalculateBrierScoreDecomposition splits the Brier score into Murphy’s components using the same equal-width binning: Reliability (calibration error, lower is better), Resolution (how much the bins separate events from non-events, higher is better), Uncertainty (the base-rate variance, fixed by the data) and WithinBinTerm, a usually small correction term (within-bin forecast variance minus twice the within-bin covariance of forecast and outcome, zero when every probability inside a bin is identical) such that Brier equals Reliability - Resolution + Uncertainty + WithinBinTerm. BrierSkillScore is one minus the Brier score over the Brier score of always predicting the base rate: 0 means no better than the base rate, 1 is perfect, negative is worse. Use it to tell whether a model’s error comes from poor calibration (large Reliability) or poor discrimination (small Resolution).

CalculateProbabilityScoringRules scores predicted probabilities with the two standard proper scoring rules — Brier score and log loss — each compared with the trivial model that always predicts the base rate via BrierSkillScore and LogLossSkillScore (one minus the ratio to that baseline; above 0 means the model adds information). CalibrationInTheLarge is the observed event rate minus the mean predicted probability, so positive means systematic under-prediction. Probabilities are clipped at epsilon (default 1e-15, must stay below 0.5) before the logarithm so a probability of exactly 0 or 1 does not make log loss infinite.

TestHosmerLemeshowCalibration runs the Hosmer-Lemeshow goodness-of-fit test: cases are sorted by predicted probability and cut into groups equal-sized bins (3 to 1000, default 10), and the observed event count in each group is compared with the count expected from the average predicted probability there. The chi-square statistic has groups - 2 degrees of freedom; a p-value below 0.05 means the predictions are significantly miscalibrated, while a large p-value is weak evidence of good calibration on a small sample and over-sensitive on a very large one. Each group’s own chi-square contribution shows where the miscalibration is concentrated.

FitCalibrationSlopeAndIntercept estimates calibration slope and intercept directly by a logistic regression of the outcome on the logit of the predicted probability. A slope near 1 with an intercept near 0 means well-calibrated probabilities; a slope below 1 means predictions are too extreme (over-confident), above 1 too timid; a non-zero intercept alongside a slope near 1 usually signals a base-rate shift rather than a ranking problem. The result’s Interpretation field states one of five readings in plain language, from “well calibrated” through “predictions are far too extreme (over-confident)” to “the recalibration could not be fitted” when the fit is impossible (for example only one outcome class, or identical probabilities throughout).

CalculateMulticlassLogLoss scores multi-class probability predictions: each row holds a probability per class (columns ordered as classNames), rows are rescaled to sum to 1 so unnormalised scores are accepted, and probabilities are clipped at epsilon. It returns the mean log loss and the multi-class Brier score (mean squared distance to the one-hot outcome, 0 to 2), an implied accuracy (share of rows where the highest probability matches the actual class), and LogLossPerActualClass/SupportPerClass so a per-class weak spot is visible. Rows containing a NaN probability are dropped.

AdjustProbabilitiesForBaseRate re-bases predicted probabilities from the event rate a model was trained at to a different real-world event rate, by the prior-shift correction: shifting every probability’s log odds by the difference between trainingBaseRate and targetBaseRate (both strictly between 0 and 1). Use it after training on a rebalanced or sampled dataset, or when the production event rate differs from training, so the output can be read as a true likelihood and compared against a cost-based threshold. Ranking and AUC are unchanged by this transform; only calibration moves. Input probabilities must lie between 0 and 1; NaN entries stay NaN in the output array.

Rates, information value and population stability (RateAndInformationValueTools)

CalculateInformationValueByCategory scores how well a categorical variable separates events from non-events with weight of evidence (WoE) and information value (IV), the standard credit-risk and fraud-scorecard screen. For each category it returns the counts, event rate, share of all events and of all non-events, and the WoE — the natural log of the event share over the non-event share, positive meaning riskier than average. TotalInformationValue sums (event share - non-event share) * WoE across categories, with the conventional rule of thumb: below 0.02 not predictive, 0.02 to 0.1 weak, 0.1 to 0.3 medium, 0.3 to 0.5 strong, above 0.5 suspiciously strong (often a leak). smoothing (default 0.5) is added to every category’s event and non-event counts whenever any category has a zero cell, so the logarithm stays finite; set it to 0 to disable and let a zero cell’s WoE come back NaN instead. Rows with a blank category or non-binary outcome are skipped and counted.

CalculateInformationValueByBins is the numeric-variable counterpart: it bins a continuous variable (EqualFrequency, the default quantile binning, or EqualWidth, both from 2 to 100 bins) and scores the bins with the same WoE/IV logic. NaN values form their own “Missing” bin rather than being dropped, so missingness itself can carry information value. WeightOfEvidenceIsMonotonic reports whether risk rises or falls steadily across the bins in order, which scorecard development usually requires.

CalculatePopulationStabilityIndexFromCounts, CalculatePopulationStabilityIndexForNumericValues and CalculatePopulationStabilityIndexForCategories are three entry points to the same Population Stability Index (PSI): the sum over bins of (current share - baseline share) * log(current share / baseline share), with the shared interpretation below 0.1 stable, 0.1 to 0.25 a moderate shift worth investigating, above 0.25 a significant shift. FromCounts takes pre-binned baseline and current counts directly (at least two bins, each count non-negative). ForNumericValues instead learns bin edges from the baseline sample only (EqualFrequency by default, 2 to 100 bins), puts current values below or above the baseline’s range into the first or last bin, and gives NaN values their own Missing bin. ForCategories compares baseline and current label frequencies directly, with categories that appear in either sample forming the bins, so a category that newly appears or disappears shows up as a large contribution to the index. In every variant, a bin with an empty share is floored at shareFloor (default 0.0001) before the logarithm, and each bin’s own contribution is returned so the source of drift is visible, not just the headline number.

TabulateEventRateBySegment tabulates a binary event rate (alert rate, fraud rate, default rate) across every value of a categorical segment, ranked from highest to lowest rate. Each row carries its count, events, event rate with a confidence interval (method selects Wilson by default, or Clopper-Pearson/Agresti-Coull/Jeffreys/Wald), share of all rows and of all events, lift against the overall rate (2 means twice the average), and a z test of that segment against every other row pooled together. SmallSample flags segments below minimumCount (default 30) as unreliable, and a homogeneity chi-square across all segments (returned alongside the rows) tests whether the rate genuinely differs by segment at all. Blank segment labels are skipped and counted.

TabulateAlertHitRatesBySegment summarises how an alerting rule or model performs per segment from one alert flag and one confirmed-event flag per case: for every segment and overall it returns the alert rate (alerts over cases), the hit rate (confirmed events among alerts, also called precision), the detection rate (confirmed events that were alerted, also called recall), false positives per true hit, the count of missed events, and Wilson intervals for both the alert and hit rates. Use it to find segments where alerts are mostly noise (low hit rate) versus segments where real events slip through (low detection rate).

CalculatePoissonRateConfidenceInterval computes an exact Garwood confidence interval for a Poisson rate — alerts per thousand accounts, cases per day — from an event count and the exposure it was observed over, in whatever unit the exposure is supplied in. Zero observed events still give a finite, non-zero upper limit, which is the rate that cannot yet be ruled out; this behaves far better than a normal approximation for rare-event rates.

ComparePoissonRates compares two Poisson rates (for example the alert rate before and after a rule change) from each period’s event count and exposure. It returns both rates, the rate ratio with an exact interval (above 1 means group 1 is higher; when group 2 has no events the ratio and its upper limit are NaN because the ratio is unbounded), the rate difference with a normal-approximation interval, and a two-sided p-value from the exact conditional binomial test — falling back to a normal approximation, with PValueMethod saying so, only once the combined count exceeds 400,000.

TestPoissonDispersion tests whether a series of counts (alerts per day, say) behaves like a Poisson process using the index of dispersion: the sum of squared deviations over the mean, chi-square distributed with n - 1 degrees of freedom under the null. VarianceToMeanRatio near 1 is consistent with Poisson; well above 1 with a small PValueOverdispersion means bursty, clustered counts that a plain Poisson model or rate interval would understate; below 1 with a small PValueUnderdispersion means unusually regular counts. A series with a zero mean or fewer than two observations cannot be tested and returns NaN throughout with an explanatory Interpretation.

Score ranking and threshold selection (ScoreRankingTools)

This is the largest single file in the group (15 tools) and underpins most model-evaluation and operating-point work.

ComputeRocCurve computes the ROC curve of a score against a 0/1 outcome, together with the area under it (AUC) and its DeLong standard error and confidence interval. Each point gives a threshold (a case is flagged when its score is at or above it), the false positive rate and the true positive rate there; the first point has a NaN threshold and sits at the origin where nothing is flagged. AUC is the chance that a random event scores above a random non-event — 0.5 is no skill, 1 is perfect, below 0.5 means the score is inverted — and Gini is 2 * AUC - 1. The result also returns the Kolmogorov-Smirnov maximum gap between the two rate curves and the Youden-optimal point (sensitivity, specificity and threshold where TPR - FPR is largest). maxPoints thins a long curve for display while AUC is always computed from every point; both classes must be present.

ComparePairedRocAucDelong compares the AUC of two different scores evaluated on the same cases, using the paired DeLong test, which accounts for the correlation between the two scores (an unpaired comparison would overstate the uncertainty). It returns both AUCs, their difference with a standard error, confidence interval, z statistic, two-sided p-value and the correlation between the two scores; a small p-value means one score genuinely ranks better than the other on this validation set. Rows where either score is NaN are dropped. It should not be used on scores measured on different cases — that needs an unpaired comparison instead.

ComputePrecisionRecallCurve computes the precision-recall curve together with the average precision (the step-wise area under the curve). Each point gives a threshold, the precision (share of flagged cases that are real events) and the recall (share of events flagged); AveragePrecision should be read against Prevalence (the precision of flagging everything), and this pairing is far more informative than ROC AUC when events are rare, as in fraud and AML. BestF1 and its threshold are returned alongside. At least one event is required.

ComputeLiftGainTable builds the classic decile (or n-group) lift and gain table: cases are ranked by score from highest to lowest and cut into groups equal-sized bands (2 to 1000, default 10, group 1 holding the highest scores). Each row gives the score range, count, events, event rate, lift (group rate over overall rate), the cumulative event rate and lift, cumulative gain (share of all events captured so far) and the Kolmogorov-Smirnov gap between the cumulative event and non-event shares at that point — read it as “reviewing the top 20 percent of cases finds X percent of events.” The maximum KS gap and the group it occurs at are returned at the top level too. Ties at a group boundary are split by input order.

ComputeKolmogorovSmirnovSeparation measures separation with the Kolmogorov-Smirnov statistic directly — the largest gap between the cumulative score distributions of the two classes — rather than deriving it from a lift table. It returns the KS value (0 no separation, 1 perfect), the threshold where the gap is largest with the sensitivity and false-positive rate there, AUC and Gini for context, and the mean and median score of each class. The description’s own rule of thumb: KS around 0.2 to 0.4 is typical of a usable fraud or credit score, and above about 0.7 is worth checking for leakage. Use the two-sample Kolmogorov-Smirnov hypothesis test (in the separate hypothesis tests tool layer) for a p-value on the same statistic.

ComputeThresholdSweep evaluates a score at many cut-offs in one call and returns a row per threshold with the confusion counts, alert rate, precision, recall, specificity, F1, F-beta, Youden’s J, Matthews correlation and, when costFalseNegative/costFalsePositive are both given, the expected cost per case. Give explicit thresholds to inspect specific cut-offs, or leave them empty to get up to maxThresholds (default 20, max 1000) spread evenly across the distinct scores observed. This is the tool to see the whole trade-off curve before choosing an operating point; the SelectThreshold* tools below automate that choice.

SelectThresholdMaximisingFBeta, SelectThresholdMaximisingYoudenIndex, SelectThresholdMaximisingMatthewsCorrelation and SelectThresholdMinimisingCost each search every distinct score as a candidate threshold and return the one that optimises a different objective, all sharing the result shape ThresholdSelectionResult (Objective, Threshold, ObjectiveValue, Achievable, Note, the full Metrics at that point, and, for the cost variant, BayesOptimalThreshold/ExpectedCostFlagNone/ExpectedCostFlagAll). F-beta maximises the weighted harmonic mean of precision and recall (beta above 1 favours recall, below 1 precision) but ignores true negatives entirely, which suits rare-event problems but not cost-sensitive ones. Youden’s J maximises sensitivity + specificity - 1, the point on the ROC curve furthest from the chance diagonal, treating a missed event and a false alert as equally costly per class regardless of how rare events are — which can flag many cases when events are rare. Matthews correlation maximises a single balanced summary of the whole confusion matrix that stays honest under class imbalance. Minimising cost takes explicit costFalseNegative/costFalsePositive (and optional costTruePositive/ costTrueNegative) and additionally reports the theoretical Bayes-optimal probability threshold (costFalsePositive / (costFalsePositive + costFalseNegative), meaningful only when the scores are calibrated probabilities) plus the cost of flagging nothing and flagging everything for comparison; if flagging nothing is cheapest, the returned threshold sits just above the highest observed score and Note says so. All four choose the highest tied threshold, which flags the fewest cases, and all require both outcome classes present.

SelectThresholdForTargetRecall finds the highest threshold — and so the fewest alerts — that still reaches at least targetRecall. SelectThresholdForTargetPrecision finds the lowest threshold that keeps precision at or above targetPrecision; if no threshold reaches that target, Achievable is false and the highest-precision point available is returned instead, with Note explaining why. SelectThresholdForAlertBudget finds the lowest threshold whose alert count stays within a capacity budget, given as either alertFraction (a share of all cases) or alertCount (an absolute number) — exactly one of the two must be supplied. Because tied scores are flagged together, the realised alert count can land below the budget; if the single highest score is tied across more cases than the budget allows, Achievable is false and the smallest possible alert set is returned.

EvaluateTopKAlertQueue answers, for a ranked queue, “if analysts review the k highest-scoring cases, how many real events do they find?” for each of several queueSizes at once. Each size returns the true positives found, precision and recall at that cut, lift (precision over the overall event rate) and the lowest score still included in the queue. Every size must be between 1 and the number of usable cases; ties at the cut are broken by input order.

CalculateOneVersusRestMulticlassAuc evaluates a multi-class probability model’s ranking quality one class at a time: for each class, how well its probability column separates that class from every other class (one-versus-rest AUC). It returns the AUC and support per class plus a macro average (every class weighted equally) and a support-weighted average. A class that never occurs, or occurs in every row, gets NaN AUC and is excluded from both averages; probabilities need not sum to 1 for this comparison, only be internally higher where that class is more likely.

Survival estimation (SurvivalEstimationTools)

Every tool in this file takes a times/events pair (time to event or censoring, and 1 if the event was actually observed or 0 if the case was censored while still event-free) and handles right-censoring correctly throughout; a row with a NaN time is dropped and counted, and a negative or infinite time is rejected outright.

EstimateKaplanMeierSurvival estimates the survival curve — the probability of still being event-free — with the Kaplan-Meier product-limit method. Each row gives the time, the number at risk just before it, the events and censorings at it, the survival probability, its Greenwood standard error, and a pointwise confidence band (LogLog by default, which stays inside 0 and 1, or Log/Plain). The result also returns the median survival time (the first time the curve drops to 0.5 or below, NaN when it never gets that low) with confidence limits, and the lower and upper quartile times. includeCensoringTimes controls whether censoring-only times get their own row, and maxRows thins a long curve while keeping the first and last rows.

EstimateKaplanMeierByGroup runs that same analysis separately for each distinct value of a groups array (for example segment, channel or treatment arm) and compares the curves with a log-rank test. Each group gets its own subject/event/censored counts, median survival with limits, quartile times, longest observation and, if evaluationTimes are given, survival with a band read at those specific times. The overall log-rank chi-square and p-value test whether the curves differ at all across the groups (NaN with only one group); a NaN median for a group means fewer than half of it had the event within follow-up.

EstimateNelsonAalenCumulativeHazard estimates the cumulative hazard function H(t) — the accumulated risk of the event up to time t — with the Nelson-Aalen estimator, allowing for censoring exactly as Kaplan-Meier does. Each row gives the cumulative hazard, its standard error, a log-scale confidence band, and exp(-H(t)) as an approximate survival curve. The slope of H(t) is the hazard rate itself: a straight line means a constant hazard, a steepening curve a rising one, which is the main reason to prefer this estimator to Kaplan-Meier when the shape of risk over time matters.

EvaluateSurvivalAtTimes reads the Kaplan-Meier curve at specific times of interest — for example the share of accounts still chargeback-free after 30, 90 and 180 days — returning, per requested time, the number still at risk, survival with its standard error and band, the Nelson-Aalen cumulative hazard, and the cumulative probability of the event (one minus survival). Before the first event, survival is exactly 1. A time beyond the longest observation returns the last estimate as an extrapolation, which should not be trusted if the final cases were censored rather than observed to fail — compare against the returned MaximumObservedTime.

CalculateSurvivalTimeQuantiles finds the times by which chosen proportions of the cohort have had the event, read off the Kaplan-Meier curve with Brookmeyer-Crowley confidence limits. The proportion 0.5 gives the median survival time; 0.9 gives the time by which 90 percent have had the event. A NaN time means the curve never drops far enough within the observed period to reach that quantile; a NaN limit means the confidence band never crosses the level.

CalculateRestrictedMeanSurvivalTime computes the restricted mean survival time (RMST): the average event-free time over the first horizon time units, equal to the area under the Kaplan-Meier curve from 0 to the horizon. Unlike the median it is always defined and easy to state plainly — “on average an account stays clean for 160 of its first 180 days” — with a standard error, confidence interval and LifetimeLost (horizon - RMST, the average time lost to the event within the horizon). HorizonBeyondLastObservation warns when the chosen horizon exceeds the longest observation, in which case the curve is extrapolated as flat beyond it.

CompareRestrictedMeanSurvivalTime compares exactly two groups by RMST up to a shared horizon: each group’s RMST, their difference (first minus second, alphabetically) with standard error, confidence interval, z statistic and p-value, plus the ratio. Because it needs no proportional-hazards assumption, it is a useful complement to the log-rank test and a Cox model when the two survival curves cross rather than running cleanly parallel.

EstimateMedianFollowUpTime estimates how long a cohort has typically been observed, using the reverse Kaplan-Meier trick: events and censoring swap roles, so the median of the resulting curve is the median follow-up that would have been seen had nobody ever had the event. This is the accepted way to report follow-up duration when events truncate observation early, since a plain median of observation times is biased downward. It returns that reverse-KM median with limits alongside the plain median and the longest observation for comparison; NaN means the reverse curve never falls to 0.5, which happens when too few cases were censored.

TestLogRankSurvivalDifference tests whether two or more groups share the same survival curve, comparing at every event time the observed events per group against what would be expected under one shared hazard. weighting selects the sensitivity profile: LogRank (default) is strongest against a constant hazard ratio, GehanBreslow and TaroneWare emphasise early differences, PetoPeto emphasises early-to-middle differences, and FlemingHarrington (with exponents flemingHarringtonP/Q) lets early or late differences be targeted explicitly. It returns per-group observed and expected events, the chi-square with groups - 1 degrees of freedom and its p-value, and, for exactly two groups under LogRank weighting only, a one-step hazard ratio of the first group versus the second with confidence limits.

Survival and hazard models (SurvivalModelTools)

FitCoxProportionalHazards fits a Cox proportional hazards regression — how numeric covariates multiply the instantaneous event risk over time, handling censoring correctly — without saving any model. The coefficient table gives, per covariate, the log hazard ratio, standard error, Wald z and p-value, the hazard ratio (exp(coefficient)) and its confidence interval: a hazard ratio of 1.5 means each extra unit of that covariate multiplies the event rate by 1.5 at every time point, below 1 lowers it, and an interval containing 1 means no clear effect. It also returns the partial log-likelihood, a likelihood-ratio test of the whole model against no covariates, Harrell’s concordance index, the Breslow baseline cumulative hazard and survival at the mean covariate profile, and — if newCovariates and predictionTimes are supplied — each new row’s relative hazard and survival probability at those times. Covariates must be numeric (encode categories as 0/1 columns first) and none may be constant; the fit is capped at 10,000 rows and 50 covariates, ties use the Breslow approximation, and Warnings flags non-convergence, fewer than 10 events per covariate, or coefficients extreme enough to suggest complete separation or collinearity.

CalculateHarrellConcordanceIndex measures how well any risk score ranks cases by time to event, allowing for censoring, independent of whether that score came from a Cox model. Among every comparable pair (the shorter-time case had the event; a tie in time counts only when exactly one of the pair had the event), it counts how often the higher-risk score belongs to the case that actually failed first — 0.5 is chance, 1 is perfect, pairs with equal scores count half. SomersD (2C - 1) and the raw pair counts are returned alongside. It is capped at 20,000 rows because every pair is examined.

FitExponentialSurvivalModel fits the simplest possible survival model: a constant hazard, by maximum likelihood, where the rate is simply events divided by total time at risk. It returns the rate with an exact confidence interval, the mean and median lifetime implied by that rate, survival with a band at any evaluationTimes requested, and MaximumAbsoluteDifferenceFromKaplanMeier — the largest gap between this constant-hazard model and the non-parametric Kaplan-Meier curve. A small gap (under roughly 0.05) supports the constant-hazard assumption; a large one means risk genuinely changes over time and a model such as FitCoxProportionalHazards or a piecewise hazard (TabulateHazardRateByInterval) is needed instead. With zero observed events the rate is 0 and the mean/median lifetime are NaN because they are unbounded.

CalculateIncidenceRatesByGroup computes person-time incidence rates by group: for each group, the event count, total time at risk, the event rate per unit time with an exact Poisson interval, and a rate ratio against a referenceGroup (defaulting to the alphabetically first group) with its own exact interval and p-value. Use it to compare event intensity across segments when follow-up lengths genuinely differ, for example chargebacks per account-year rather than per account. A group with zero time at risk cannot be rated.

TabulateHazardRateByInterval estimates a piecewise-constant hazard — the event rate per unit time within consecutive time windows defined by breaks (strictly increasing, starting at 0 or more, with a final open-ended interval after the last value). Each interval reports entering subjects, events, censored cases, the person-time at risk within it, the hazard rate with an exact Poisson interval, and the conditional event probability implied by treating that rate as constant through the interval. A falling sequence of rates across intervals means early-life risk; a rising sequence means wear-out.

BuildActuarialLifeTable builds a classical actuarial (life table) survival analysis over the same kind of fixed breaks, the natural choice for grouped or very large data where exact event times are not retained. Each interval reports subjects entering, those withdrawn (censored) during it, events, the effective number at risk (entering minus half the withdrawals — the actuarial assumption that censoring happens evenly through the interval), the conditional event probability with its standard error, cumulative survival at the interval’s end with a Greenwood standard error, and the midpoint hazard rate. Unlike Kaplan-Meier, which this file’s other tools use, the life table trades the exact censoring assumption for tolerance of coarse, grouped time data.

CalculateCumulativeIncidenceCompetingRisks estimates the cumulative incidence of each event type when several mutually exclusive event types compete for the same subjects, using the Aalen-Johansen estimator: the probability that a case has experienced event type k by time t, allowing for the chance it was removed first by a different event type. Event-type codes are 0 for censored and 1, 2, 3 and so on for each competing event; every row gives the number at risk, events of each type at that time, the overall event-free survival and the cumulative incidence per type, which together with survival always sum to 1. The description makes the key point explicit: running Kaplan-Meier on a single event type alone, ignoring the others, would overstate that type’s probability, because it implicitly treats removal by a competing event as if the subject had simply stayed at risk. No variance is returned for this estimator.