Skip to content

Metrics

ConfusionMatrix dataclass

Result object returned by rapidstats.confusion_matrix

Attributes:

Name Type Description
tn float

↑Count of True Negatives; y_true == False and y_pred == False

fp float

↓Count of False Positives; y_true == False and y_pred == True

fn float

↓Count of False Negatives; y_true == True and y_pred == False

tp float

↑Count of True Positives; y_true == True, y_pred == True

tpr float

↑True Positive Rate, Recall, Sensitivity; Probability that an actual positive will be predicted positive; \( \frac{TP}{TP + FN} \)

fpr float

↓False Positive Rate, Type I Error; Probability that an actual negative will be predicted positive; \( \frac{FP}{FP + TN} \)

fnr float

↓False Negative Rate, Type II Error; Probability an actual positive will be predicted negative; \( \frac{FN}{TP + FN} \)

tnr float

↑True Negative Rate, Specificity; Probability an actual negative will be predicted negative; \( \frac{TN}{FP + TN} \)

prevalence float

Prevalence; Proportion of positive classes; \( \frac{TP + FN}{TN + FP + FN + TP} \)

prevalence_threshold float

Prevalence Threshold; \( \frac{\sqrt{TPR \times FPR} - FPR}{TPR - FPR} \)

informedness float

↑Informedness, Youden's J; \( TPR + TNR - 1 \)

precision float

↑Precision, Positive Predicted Value (PPV); Probability a predicted positive was actually correct; \( \frac{TP}{TP + FP} \)

false_omission_rate float

↓False Omission Rate (FOR); Proportion of predicted negatives that were wrong \( \frac{FN}{FN + TN} \)

plr float

↑Positive Likelihood Ratio, LR+; \( \frac{TPR}{FPR} \)

nlr float

Negative Likelihood Ratio, LR-; \( \frac{FNR}{TNR} \)

acc float

↑Accuracy (ACC); Probability of a correct prediction; \( \frac{TP + TN}{TN + FP + FN + TP} \)

balanced_accuracy float

↑Balanced Accuracy (BA); \( \frac{TP + TN}{2} \)

f1 float

↑F1; Harmonic mean of Precision and Recall; \( \frac{2 \times PPV \times TPR}{PPV + TPR} \)

folkes_mallows_index float

↑Folkes Mallows Index (FM); \( \sqrt{PPV \times TPR} \)

mcc float

↑Matthew Correlation Coefficient (MCC), Yule Phi Coefficient; \( \sqrt{TPR \times TNR \times PPV \times NPV} - \sqrt{FNR \times FPR \times FOR \times FDR} \)

threat_score float

↑Threat Score (TS), Critical Success Index (CSI), Jaccard Index; \( \frac{TP}{TP + FN + FP} \)

markedness float

Markedness (MP), deltaP; \( PPV + NPV - 1 \)

fdr float

↓False Discovery Rate, Proportion of predicted positives that are wrong; \( \frac{FP}{TP + FP} \)

↑npv float

Negative Predictive Value; Proportion of predicted negatives that are correct; \( \frac{TN}{FN + TN} \)

dor float

Diagnostic Odds Ratio; \( \frac{LR+}{LR-} \)

ppr float

Predicted Positive Ratio; Proportion that are predicted positive; ( \frac{TP + FP}{TN + FP + FN + TP})

pnr float

Predicted Negative Ratio; Proportion that are predicted negative; ( \frac{TN + FN}{TN + FP + FN + TP})

Source code in python/rapidstats/_metrics.py
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
@dataclasses.dataclass
class ConfusionMatrix:
    r"""Result object returned by `rapidstats.confusion_matrix`

    Attributes
    ----------
    tn : float
        ↑Count of True Negatives; y_true == False and y_pred == False
    fp : float
        ↓Count of False Positives; y_true == False and y_pred == True
    fn : float
        ↓Count of False Negatives; y_true == True and y_pred == False
    tp : float
        ↑Count of True Positives; y_true == True, y_pred == True
    tpr : float
        ↑True Positive Rate, Recall, Sensitivity; Probability that an actual positive
        will be predicted positive; \( \frac{TP}{TP + FN} \)
    fpr : float
        ↓False Positive Rate, Type I Error; Probability that an actual negative will
        be predicted positive; \( \frac{FP}{FP + TN} \)
    fnr : float
        ↓False Negative Rate, Type II Error; Probability an actual positive will be
        predicted negative; \( \frac{FN}{TP + FN} \)
    tnr : float
        ↑True Negative Rate, Specificity; Probability an actual negative will be
        predicted negative; \( \frac{TN}{FP + TN} \)
    prevalence : float
        Prevalence; Proportion of positive classes; \( \frac{TP + FN}{TN + FP + FN + TP} \)
    prevalence_threshold : float
        Prevalence Threshold; \( \frac{\sqrt{TPR \times FPR} - FPR}{TPR - FPR} \)
    informedness : float
        ↑Informedness, Youden's J; \( TPR + TNR - 1 \)
    precision : float
        ↑Precision, Positive Predicted Value (PPV); Probability a predicted positive was
        actually correct; \( \frac{TP}{TP + FP} \)
    false_omission_rate : float
        ↓False Omission Rate (FOR); Proportion of predicted negatives that were wrong
        \( \frac{FN}{FN + TN} \)
    plr : float
        ↑Positive Likelihood Ratio, LR+; \( \frac{TPR}{FPR} \)
    nlr : float
        Negative Likelihood Ratio, LR-; \( \frac{FNR}{TNR} \)
    acc : float
        ↑Accuracy (ACC); Probability of a correct prediction; \( \frac{TP + TN}{TN + FP + FN + TP} \)
    balanced_accuracy : float
        ↑Balanced Accuracy (BA); \( \frac{TP + TN}{2} \)
    f1 : float
        ↑F1; Harmonic mean of Precision and Recall; \( \frac{2 \times PPV \times TPR}{PPV + TPR} \)
    folkes_mallows_index : float
        ↑Folkes Mallows Index (FM); \( \sqrt{PPV \times TPR} \)
    mcc : float
        ↑Matthew Correlation Coefficient (MCC), Yule Phi Coefficient; \( \sqrt{TPR \times TNR \times PPV \times NPV} - \sqrt{FNR \times FPR \times FOR \times FDR} \)
    threat_score : float
        ↑Threat Score (TS), Critical Success Index (CSI), Jaccard Index; \( \frac{TP}{TP + FN + FP} \)
    markedness : float
        Markedness (MP), deltaP; \( PPV + NPV - 1 \)
    fdr : float
        ↓False Discovery Rate, Proportion of predicted positives that are wrong; \( \frac{FP}{TP + FP} \)
    ↑npv : float
        Negative Predictive Value; Proportion of predicted negatives that are correct; \( \frac{TN}{FN + TN} \)
    dor : float
        Diagnostic Odds Ratio; \( \frac{LR+}{LR-} \)
    ppr : float
        Predicted Positive Ratio; Proportion that are predicted positive; \( \frac{TP + FP}{TN + FP + FN + TP})
    pnr : float
        Predicted Negative Ratio; Proportion that are predicted negative; \( \frac{TN + FN}{TN + FP + FN + TP})
    """

    tn: float
    fp: float
    fn: float
    tp: float
    tpr: float
    fpr: float
    fnr: float
    tnr: float
    prevalence: float
    prevalence_threshold: float
    informedness: float
    precision: float
    false_omission_rate: float
    plr: float
    nlr: float
    acc: float
    balanced_accuracy: float
    f1: float
    folkes_mallows_index: float
    mcc: float
    threat_score: float
    markedness: float
    fdr: float
    npv: float
    dor: float
    ppr: float
    pnr: float

    def to_polars(self) -> pl.DataFrame:
        """Convert the dataclass to a long Polars DataFrame with columns `metric` and
        `value`.

        Returns
        -------
        pl.DataFrame
            DataFrame with columns `metric` and `value`
        """
        dct = self.__dict__

        return pl.DataFrame({"metric": dct.keys(), "value": dct.values()})

to_polars()

Convert the dataclass to a long Polars DataFrame with columns metric and value.

Returns:

Type Description
DataFrame

DataFrame with columns metric and value

Source code in python/rapidstats/_metrics.py
160
161
162
163
164
165
166
167
168
169
170
171
def to_polars(self) -> pl.DataFrame:
    """Convert the dataclass to a long Polars DataFrame with columns `metric` and
    `value`.

    Returns
    -------
    pl.DataFrame
        DataFrame with columns `metric` and `value`
    """
    dct = self.__dict__

    return pl.DataFrame({"metric": dct.keys(), "value": dct.values()})

adverse_impact_ratio(y_pred, protected, control)

Computes the Adverse Impact Ratio (AIR), which is the ratio of negative predictions for the protected class and the control class. The ideal ratio is 1. For example, in an underwriting context, this means that the model is equally as likely to approve protected applicants as it is unprotected applicants, given that the model score is probability of bad.

Parameters:

Name Type Description Default
y_pred ArrayLike

Predicted negative

required
protected ArrayLike

An array of booleans identifying the protected class

required
control ArrayLike

An array of booleans identifying the control class

required

Returns:

Type Description
float

Adverse Impact Ratio (AIR)

Source code in python/rapidstats/_metrics.py
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
def adverse_impact_ratio(
    y_pred: ArrayLike,
    protected: ArrayLike,
    control: ArrayLike,
) -> float:
    """Computes the Adverse Impact Ratio (AIR), which is the ratio of negative
    predictions for the protected class and the control class. The ideal ratio is 1.
    For example, in an underwriting context, this means that the model is equally as
    likely to approve protected applicants as it is unprotected applicants, given that
    the model score is probability of bad.

    Parameters
    ----------
    y_pred : ArrayLike
        Predicted negative
    protected : ArrayLike
        An array of booleans identifying the protected class
    control : ArrayLike
        An array of booleans identifying the control class

    Returns
    -------
    float
        Adverse Impact Ratio (AIR)
    """
    return _adverse_impact_ratio(
        pl.DataFrame(
            {"y_pred": y_pred, "protected": protected, "control": control}
        ).cast(pl.Boolean)
    )

adverse_impact_ratio_at_thresholds(y_score, protected, control, thresholds=None, strategy='auto')

Computes the Adverse Impact Ratio (AIR) at each threshold of y_score. See rapidstats.adverse_impact_ratio for more details. When the strategy is cum_sum, computes

for t in y_score:
    is_predicted_negative = y_score < t
    adverse_impact_ratio(is_predicted_negative, protected, control)

Parameters:

Name Type Description Default
y_score ArrayLike

Predicted scores

required
protected ArrayLike

An array of booleans identifying the protected class

required
control ArrayLike

An array of booleans identifying the control class

required
thresholds Optional[list[float]]

The thresholds to compute is_predicted_negative at, i.e. y_score < t. If None, uses every score present in y_score, by default None

None
strategy LoopStrategy

Computation method, by default "auto"

'auto'

Returns:

Type Description
DataFrame

A DataFrame of threshold and air

Source code in python/rapidstats/_metrics.py
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
def adverse_impact_ratio_at_thresholds(
    y_score: ArrayLike,
    protected: ArrayLike,
    control: ArrayLike,
    thresholds: Optional[list[float]] = None,
    strategy: LoopStrategy = "auto",
) -> pl.DataFrame:
    """Computes the Adverse Impact Ratio (AIR) at each threshold of `y_score`. See
    [rapidstats.adverse_impact_ratio][] for more details. When the `strategy` is
    `cum_sum`, computes


    ``` py
    for t in y_score:
        is_predicted_negative = y_score < t
        adverse_impact_ratio(is_predicted_negative, protected, control)
    ```

    Parameters
    ----------
    y_score : ArrayLike
        Predicted scores
    protected : ArrayLike
        An array of booleans identifying the protected class
    control : ArrayLike
        An array of booleans identifying the control class
    thresholds : Optional[list[float]], optional
        The thresholds to compute `is_predicted_negative` at, i.e. y_score < t. If None,
        uses every score present in `y_score`, by default None
    strategy : LoopStrategy, optional
        Computation method, by default "auto"

    Returns
    -------
    pl.DataFrame
        A DataFrame of `threshold` and `air`
    """
    df = pl.DataFrame(
        {"y_score": y_score, "protected": protected, "control": control}
    ).with_columns(pl.col("protected", "control").cast(pl.Boolean))

    strategy = _set_loop_strategy(thresholds, strategy)

    if strategy == "loop":

        def _air(t):
            return {
                "threshold": t,
                "air": _adverse_impact_ratio(
                    df.select(
                        pl.col("y_score").lt(t).alias("y_pred"), "protected", "control"
                    )
                ),
            }

        airs = _run_concurrent(_air, set(thresholds or y_score))

        res = pl.LazyFrame(airs)
    elif strategy == "cum_sum":
        res = _air_at_thresholds_core(df, thresholds)

    return res.pipe(_fill_infinite, None).fill_nan(None).collect()

brier_loss(y_true, y_score)

Computes the Brier loss (smaller is better). The Brier loss measures the mean squared difference between the predicted scores and the ground truth target. Calculated as:

\[ \frac{1}{N} \sum_{i=1}^N (yt_i - ys_i)^2 \]

where \( yt \) is y_true and \( ys \) is y_score.

Parameters:

Name Type Description Default
y_true ArrayLike

Ground truth target

required
y_score ArrayLike

Predicted scores

required

Returns:

Type Description
float

Brier loss

Source code in python/rapidstats/_metrics.py
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
def brier_loss(y_true: ArrayLike, y_score: ArrayLike) -> float:
    r"""Computes the Brier loss (smaller is better). The Brier loss measures the mean
    squared difference between the predicted scores and the ground truth target.
    Calculated as:

    \[ \frac{1}{N} \sum_{i=1}^N (yt_i - ys_i)^2 \]

    where \( yt \) is `y_true` and \( ys \) is `y_score`.

    Parameters
    ----------
    y_true : ArrayLike
        Ground truth target
    y_score : ArrayLike
        Predicted scores

    Returns
    -------
    float
        Brier loss
    """
    df = _y_true_y_score_to_df(y_true, y_score)

    return _brier_loss(df)

confusion_matrix(y_true, y_pred)

Computes confusion matrix metrics (TP, FP, TN, FN, TPR, F1, etc.).

Parameters:

Name Type Description Default
y_true ArrayLike

Ground truth target

required
y_pred ArrayLike

Predicted target

required

Returns:

Type Description
ConfusionMatrix

Dataclass of confusion matrix metrics

Source code in python/rapidstats/_metrics.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
def confusion_matrix(y_true: ArrayLike, y_pred: ArrayLike) -> ConfusionMatrix:
    """Computes confusion matrix metrics (TP, FP, TN, FN, TPR, F1, etc.).

    Parameters
    ----------
    y_true : ArrayLike
        Ground truth target
    y_pred : ArrayLike
        Predicted target

    Returns
    -------
    ConfusionMatrix
        Dataclass of confusion matrix metrics
    """
    df = _y_true_y_pred_to_df(y_true, y_pred)

    return ConfusionMatrix(*_confusion_matrix(df))

confusion_matrix_at_thresholds(y_true, y_score, thresholds=None, metrics=DefaultConfusionMatrixMetrics, strategy='auto')

Computes the confusion matrix at each threshold. When the strategy is "cum_sum", computes

for t in y_score:
    y_pred = y_score >= t
    confusion_matrix(y_true, y_pred)

using fast DataFrame operations.

Parameters:

Name Type Description Default
y_true ArrayLike

Ground truth target

required
y_score ArrayLike

Predicted scores

required
thresholds Optional[list[float]]

The thresholds to compute y_pred at, i.e. y_score >= t. If None, uses every score present in y_score, by default None

None
metrics Iterable[ConfusionMatrixMetric]

The metrics to compute, by default DefaultConfusionMatrixMetrics

DefaultConfusionMatrixMetrics
strategy LoopStrategy

Computation method, by default "auto"

'auto'

Returns:

Type Description
DataFrame

A Polars DataFrame of threshold, metric, and value

Source code in python/rapidstats/_metrics.py
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
def confusion_matrix_at_thresholds(
    y_true: ArrayLike,
    y_score: ArrayLike,
    thresholds: Optional[list[float]] = None,
    metrics: Iterable[ConfusionMatrixMetric] = DefaultConfusionMatrixMetrics,
    strategy: LoopStrategy = "auto",
) -> pl.DataFrame:
    """Computes the confusion matrix at each threshold. When the `strategy` is
    "cum_sum", computes

    ``` py
    for t in y_score:
        y_pred = y_score >= t
        confusion_matrix(y_true, y_pred)
    ```

    using fast DataFrame operations.

    Parameters
    ----------
    y_true : ArrayLike
        Ground truth target
    y_score : ArrayLike
        Predicted scores
    thresholds : Optional[list[float]], optional
        The thresholds to compute `y_pred` at, i.e. y_score >= t. If None,
        uses every score present in `y_score`, by default None
    metrics : Iterable[ConfusionMatrixMetric], optional
        The metrics to compute, by default DefaultConfusionMatrixMetrics
    strategy : LoopStrategy, optional
        Computation method, by default "auto"

    Returns
    -------
    pl.DataFrame
        A Polars DataFrame of `threshold`, `metric`, and `value`
    """
    strategy = _set_loop_strategy(thresholds, strategy)

    if strategy == "loop":
        df = _y_true_y_score_to_df(y_true, y_score)

        def _cm(t):
            return (
                confusion_matrix(df["y_true"], df["y_score"].ge(t))
                .to_polars()
                .with_columns(pl.lit(t).alias("threshold"))
            )

        cms: list[pl.DataFrame] = _run_concurrent(_cm, set(thresholds or y_score))

        return pl.concat(cms, how="vertical").fill_nan(None)
    elif strategy == "cum_sum":
        return (
            pl.LazyFrame({"y_true": y_true, "threshold": y_score})
            .with_columns(pl.col("y_true").cast(pl.Boolean))
            .drop_nulls()
            .pipe(_base_confusion_matrix_at_thresholds)
            .pipe(_full_confusion_matrix_from_base)
            .select("threshold", *metrics)
            .unique("threshold")
            .pipe(_map_to_thresholds, thresholds)
            .drop("_threshold_actual", strict=False)
            .unpivot(index="threshold")
            .rename({"variable": "metric"})
            .collect()
        )

max_ks(y_true, y_score)

Performs the two-sample Kolmogorov-Smirnov test on the predicted scores of the ground truth positive and ground truth negative classes. The KS test measures the highest distance between two CDFs, so the Max-KS metric measures how well the model separates two classes. In pseucode:

df = Frame(y_true, y_score)
class0 = df.filter(~y_true)["y_score"]
class1 = df.filter(y_true)["y_score"]

ks(class0, class1)

Parameters:

Name Type Description Default
y_true ArrayLike

Ground truth target

required
y_score ArrayLike

Predicted scores

required

Returns:

Type Description
float

Max-KS

Source code in python/rapidstats/_metrics.py
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
def max_ks(y_true: ArrayLike, y_score: ArrayLike) -> float:
    """Performs the two-sample Kolmogorov-Smirnov test on the predicted scores of the
    ground truth positive and ground truth negative classes. The KS test measures the
    highest distance between two CDFs, so the Max-KS metric measures how well the model
    separates two classes. In pseucode:

    ``` py
    df = Frame(y_true, y_score)
    class0 = df.filter(~y_true)["y_score"]
    class1 = df.filter(y_true)["y_score"]

    ks(class0, class1)
    ```

    Parameters
    ----------
    y_true : ArrayLike
        Ground truth target
    y_score : ArrayLike
        Predicted scores

    Returns
    -------
    float
        Max-KS
    """
    df = _y_true_y_score_to_df(y_true, y_score)

    return _max_ks(df)

mean(y)

Computes the mean of the input array.

Parameters:

Name Type Description Default
y ArrayLike

A 1D-array of numbers

required

Returns:

Type Description
float

Mean

Source code in python/rapidstats/_metrics.py
273
274
275
276
277
278
279
280
281
282
283
284
285
286
def mean(y: ArrayLike) -> float:
    """Computes the mean of the input array.

    Parameters
    ----------
    y : ArrayLike
        A 1D-array of numbers

    Returns
    -------
    float
        Mean
    """
    return _mean(pl.DataFrame({"y": y}))

mean_squared_error(y_true, y_score)

Computes Mean Squared Error (MSE) as

\[ \frac{1}{N} \sum_{i=1}^{N} (yt_i - ys_i)^2 \]

where \( yt \) is y_true and \( ys \) is y_score.

Parameters:

Name Type Description Default
y_true ArrayLike

Ground truth target

required
y_score ArrayLike

Predicted scores

required

Returns:

Type Description
float

Mean Squared Error (MSE)

Source code in python/rapidstats/_metrics.py
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
def mean_squared_error(y_true: ArrayLike, y_score: ArrayLike) -> float:
    r"""Computes Mean Squared Error (MSE) as

    \[ \frac{1}{N} \sum_{i=1}^{N} (yt_i - ys_i)^2 \]

    where \( yt \) is `y_true` and \( ys \) is `y_score`.

    Parameters
    ----------
    y_true : ArrayLike
        Ground truth target
    y_score : ArrayLike
        Predicted scores

    Returns
    -------
    float
        Mean Squared Error (MSE)
    """
    return _mean_squared_error(_regression_to_df(y_true, y_score))

predicted_positive_ratio_at_thresholds(y_score, thresholds=None, strategy='auto')

Computes the Predicted Positive Ratio (PPR) at each threshold, where the PPR is the ratio of predicted positive to the total, and a positive is defined as y_score >= threshold.

Parameters:

Name Type Description Default
y_score ArrayLike

Predicted scores

required
thresholds Optional[list[float]]

The thresholds to compute y_pred at, i.e. y_score >= t. If None, uses every score present in y_score, by default None

None
strategy LoopStrategy

Computation method, by default "auto"

'auto'

Returns:

Type Description
DataFrame

A DataFrame of threshold and ppr

Source code in python/rapidstats/_metrics.py
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
def predicted_positive_ratio_at_thresholds(
    y_score: ArrayLike,
    thresholds: Optional[list[float]] = None,
    strategy: LoopStrategy = "auto",
) -> pl.DataFrame:
    """Computes the Predicted Positive Ratio (PPR) at each threshold, where the PPR is
    the ratio of predicted positive to the total, and a positive is defined as
    `y_score` >= threshold.

    Parameters
    ----------
    y_score : ArrayLike
        Predicted scores
    thresholds : Optional[list[float]], optional
        The thresholds to compute `y_pred` at, i.e. y_score >= t. If None,
        uses every score present in `y_score`, by default None
    strategy : LoopStrategy, optional
        Computation method, by default "auto"

    Returns
    -------
    pl.DataFrame
        A DataFrame of `threshold` and `ppr`
    """
    strategy = _set_loop_strategy(y_score, strategy)

    if strategy == "loop":
        s = pl.Series(y_score).drop_nulls()

        def _ppr(t: float) -> float:
            return {"threshold": t, "ppr": s.ge(t).mean()}

        return pl.DataFrame(_run_concurrent(_ppr, set(thresholds or y_score)))
    elif strategy == "cum_sum":
        return (
            pl.LazyFrame({"y_score": y_score})
            .drop_nulls()
            .sort("y_score", descending=True)
            .with_row_index("cumulative_predicted_positive", offset=1)
            .with_columns(
                pl.col("cumulative_predicted_positive").truediv(pl.len()).alias("ppr")
            )
            .rename({"y_score": "threshold"})
            .select("threshold", "ppr")
            .unique("threshold")
            .pipe(_map_to_thresholds, thresholds)
            .drop("_threshold_actual", strict=False)
            .collect()
        )

roc_auc(y_true, y_score)

Computes Area Under the Receiver Operating Characteristic Curve.

Parameters:

Name Type Description Default
y_true ArrayLike

Ground truth target

required
y_score ArrayLike

Predicted scores

required

Returns:

Type Description
float

ROC-AUC

Source code in python/rapidstats/_metrics.py
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
def roc_auc(y_true: ArrayLike, y_score: ArrayLike) -> float:
    """Computes Area Under the Receiver Operating Characteristic Curve.

    Parameters
    ----------
    y_true : ArrayLike
        Ground truth target
    y_score : ArrayLike
        Predicted scores

    Returns
    -------
    float
        ROC-AUC
    """
    df = _y_true_y_score_to_df(y_true, y_score).with_columns(
        pl.col("y_true").cast(pl.Float64)
    )

    return _roc_auc(df)

root_mean_squared_error(y_true, y_score)

Computes Root Mean Squared Error (RMSE) as

\[ \sqrt{\frac{1}{N} \sum_{i=1}^{N} (yt_i - ys_i)^2} \]

where \( yt \) is y_true and \( ys \) is y_score.

Parameters:

Name Type Description Default
y_true ArrayLike

Ground truth target

required
y_score ArrayLike

Predicted scores

required

Returns:

Type Description
float

Root Mean Squared Error (RMSE)

Source code in python/rapidstats/_metrics.py
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
def root_mean_squared_error(y_true: ArrayLike, y_score: ArrayLike) -> float:
    r"""Computes Root Mean Squared Error (RMSE) as

    \[ \sqrt{\frac{1}{N} \sum_{i=1}^{N} (yt_i - ys_i)^2} \]

    where \( yt \) is `y_true` and \( ys \) is `y_score`.

    Parameters
    ----------
    y_true : ArrayLike
        Ground truth target
    y_score : ArrayLike
        Predicted scores

    Returns
    -------
    float
        Root Mean Squared Error (RMSE)
    """
    return _root_mean_squared_error(_regression_to_df(y_true, y_score))