Skip to content

Binary classification stats

BinaryClassificationStats dataclass

Binary classification statistic expressions.

Source code in src/pheval/analyse/binary_classification_stats.py
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 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
@dataclass(frozen=True)
class BinaryClassificationStats:
    """Binary classification statistic expressions."""

    SENSITIVITY = (
        pl.when((pl.col("true_positives") + pl.col("false_negatives")) != 0)
        .then(pl.col("true_positives") / (pl.col("true_positives") + pl.col("false_negatives")))
        .otherwise(0.0)
        .alias("sensitivity")
    )

    SPECIFICITY = (
        pl.when((pl.col("true_negatives") + pl.col("false_positives")) != 0)
        .then(pl.col("true_negatives") / (pl.col("true_negatives") + pl.col("false_positives")))
        .otherwise(0.0)
        .alias("specificity")
    )

    PRECISION = (
        pl.when((pl.col("true_positives") + pl.col("false_positives")) != 0)
        .then(pl.col("true_positives") / (pl.col("true_positives") + pl.col("false_positives")))
        .otherwise(0.0)
        .alias("precision")
    )

    NEGATIVE_PREDICTIVE_VALUE = (
        pl.when((pl.col("true_negatives") + pl.col("false_negatives")) != 0)
        .then(pl.col("true_negatives") / (pl.col("true_negatives") + pl.col("false_negatives")))
        .otherwise(0.0)
        .alias("negative_predictive_value")
    )

    FALSE_POSITIVE_RATE = (
        pl.when((pl.col("false_positives") + pl.col("true_negatives")) != 0)
        .then(pl.col("false_positives") / (pl.col("false_positives") + pl.col("true_negatives")))
        .otherwise(0.0)
        .alias("false_positive_rate")
    )

    FALSE_DISCOVERY_RATE = (
        pl.when((pl.col("false_positives") + pl.col("true_positives")) != 0)
        .then(pl.col("false_positives") / (pl.col("false_positives") + pl.col("true_positives")))
        .otherwise(0.0)
        .alias("false_discovery_rate")
    )

    FALSE_NEGATIVE_RATE = (
        pl.when((pl.col("false_negatives") + pl.col("true_positives")) != 0)
        .then(pl.col("false_negatives") / (pl.col("false_negatives") + pl.col("true_positives")))
        .otherwise(0.0)
        .alias("false_negative_rate")
    )

    ACCURACY = (
        pl.when(
            (
                pl.col("true_positives")
                + pl.col("false_positives")
                + pl.col("true_negatives")
                + pl.col("false_negatives")
            )
            != 0
        )
        .then(
            (pl.col("true_positives") + pl.col("true_negatives"))
            / (
                pl.col("true_positives")
                + pl.col("false_positives")
                + pl.col("true_negatives")
                + pl.col("false_negatives")
            )
        )
        .otherwise(0.0)
        .alias("accuracy")
    )

    F1_SCORE = (
        pl.when(2 * (pl.col("true_positives") + pl.col("false_positives") + pl.col("false_negatives")) != 0)
        .then(
            2
            * pl.col("true_positives")
            / (2 * pl.col("true_positives") + pl.col("false_positives") + pl.col("false_negatives"))
        )
        .otherwise(0.0)
        .alias("f1_score")
    )

    MATTHEWS_CORRELATION_COEFFICIENT = (
        pl.when(
            (
                (pl.col("true_positives") + pl.col("false_positives"))
                * (pl.col("true_positives") + pl.col("false_negatives"))
                * (pl.col("true_negatives") + pl.col("false_positives"))
                * (pl.col("true_negatives") + pl.col("false_negatives"))
            )
            > 0
        )
        .then(
            (
                (pl.col("true_positives") * pl.col("true_negatives"))
                - (pl.col("false_positives") * pl.col("false_negatives"))
            )
            / (
                (pl.col("true_positives") + pl.col("false_positives"))
                * (pl.col("true_positives") + pl.col("false_negatives"))
                * (pl.col("true_negatives") + pl.col("false_positives"))
                * (pl.col("true_negatives") + pl.col("false_negatives"))
            ).sqrt()
        )
        .otherwise(0.0)
        .alias("matthews_correlation_coefficient")
    )

ConfusionMatrix dataclass

Define logical conditions for computing a confusion matrix using Polars expressions.

Attributes:

Name Type Description
TRUE_POSITIVES Expr

Condition identifying true positive cases, where rank == 1 and true_positive is True.

FALSE_POSITIVES Expr

Condition identifying false positive cases, where rank == 1 and true_positive is False.

TRUE_NEGATIVES Expr

Condition identifying true negative cases, where rank != 1 and true_positive is False.

FALSE_NEGATIVES Expr

Condition identifying false negative cases, where rank != 1 and true_positive is True.

Source code in src/pheval/analyse/binary_classification_stats.py
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@dataclass(frozen=True)
class ConfusionMatrix:
    """
    Define logical conditions for computing a confusion matrix using Polars expressions.

    Attributes:
        TRUE_POSITIVES (pl.Expr): Condition identifying true positive cases,
            where `rank == 1` and `true_positive` is `True`.
        FALSE_POSITIVES (pl.Expr): Condition identifying false positive cases,
            where `rank == 1` and `true_positive` is `False`.
        TRUE_NEGATIVES (pl.Expr): Condition identifying true negative cases,
            where `rank != 1` and `true_positive` is `False`.
        FALSE_NEGATIVES (pl.Expr): Condition identifying false negative cases,
            where `rank != 1` and `true_positive` is `True`.
    """

    TRUE_POSITIVES = (pl.col("rank") == 1) & (pl.col("true_positive"))
    FALSE_POSITIVES = (pl.col("rank") == 1) & (~pl.col("true_positive"))
    TRUE_NEGATIVES = (pl.col("rank") != 1) & (~pl.col("true_positive"))
    FALSE_NEGATIVES = (pl.col("rank") != 1) & (pl.col("true_positive"))

compute_confusion_matrix(run_identifier, result_scan)

Computes binary classification statistics.

Parameters:

Name Type Description Default
run_identifier str

The identifier for the run.

required
result_scan LazyFrame

The LazyFrame containing the results for the directory.

required

Returns:

Type Description
LazyFrame

pl.LazyFrame: The LazyFrame containing the binary classification statistics.

Source code in src/pheval/analyse/binary_classification_stats.py
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
172
173
174
175
176
177
178
179
180
181
182
183
def compute_confusion_matrix(run_identifier: str, result_scan: pl.LazyFrame) -> pl.LazyFrame:
    """
    Computes binary classification statistics.

    Args:
        run_identifier (str): The identifier for the run.
        result_scan (pl.LazyFrame): The LazyFrame containing the results for the directory.

    Returns:
        pl.LazyFrame: The LazyFrame containing the binary classification statistics.
    """
    logger = get_logger()
    logger.info(f"Computing binary classification statistics for {run_identifier}")
    confusion_matrix = result_scan.select(
        [
            pl.lit(run_identifier).alias("run_identifier"),
            ConfusionMatrix.TRUE_POSITIVES.sum().alias("true_positives").cast(pl.Int64),
            ConfusionMatrix.FALSE_POSITIVES.sum().alias("false_positives").cast(pl.Int64),
            ConfusionMatrix.TRUE_NEGATIVES.sum().alias("true_negatives").cast(pl.Int64),
            ConfusionMatrix.FALSE_NEGATIVES.sum().alias("false_negatives").cast(pl.Int64),
        ]
    )
    return confusion_matrix.select(
        [
            pl.col("run_identifier"),
            pl.col("true_positives"),
            pl.col("false_positives"),
            pl.col("true_negatives"),
            pl.col("false_negatives"),
            BinaryClassificationStats.SENSITIVITY,
            BinaryClassificationStats.SPECIFICITY,
            BinaryClassificationStats.PRECISION,
            BinaryClassificationStats.NEGATIVE_PREDICTIVE_VALUE,
            BinaryClassificationStats.FALSE_POSITIVE_RATE,
            BinaryClassificationStats.FALSE_DISCOVERY_RATE,
            BinaryClassificationStats.FALSE_NEGATIVE_RATE,
            BinaryClassificationStats.ACCURACY,
            BinaryClassificationStats.F1_SCORE,
            BinaryClassificationStats.MATTHEWS_CORRELATION_COEFFICIENT,
        ]
    )