Metrics fbeta perclass - CyrilB1531/lodestar GitHub Wiki
Home › Metrics › Classification metrics
F-beta for every class, in label order.
public static double[] PerClass(ConfusionMatrix cm, double beta, ZeroDivision zeroDivision = ZeroDivision.Zero)
public static double[] PerClass(ReadOnlySpan<int> yTrue, ReadOnlySpan<int> yPred, double beta, ZeroDivision zeroDivision = ZeroDivision.Zero, ReadOnlySpan<int> labels = default, ReadOnlySpan<double> sampleWeight = default)Parameters — cm is a matrix already counted, or pass yTrue and yPred. beta is the
weight
of recall relative to precision. zeroDivision decides an undefined per-class score, labels
fixes
the label set and its order, and sampleWeight weights the samples.
Returns — a fresh double[], one entry per label, in the matrix's label order.
Exceptions — ArgumentOutOfRangeException when beta is negative or NaN — positive infinity scores the recall, as fbeta_score does
(#1466) — and when beta is finite but its
square overflows, past √double.MaxValue ≈ 1.3407807929942596e154, where fbeta_score's beta ** 2
raises OverflowError (#1540);
ArgumentNullException when cm is null; ArgumentException when the label spans disagree in
length or are empty. A sampleWeight holding NaN or an infinity is refused with "Input sample_weight contains NaN." or its infinity counterpart, and one that is zero throughout with "Sample weights must contain at least one non-zero number." — both ArgumentException naming sampleWeight, as scikit-learn's _check_sample_weight refuses them.
Example — both classes at beta = 2.
using Lodestar.Metrics;
int[] yTrue = [1, 1, 1, 1, 0, 0, 0, 0];
int[] yPred = [1, 1, 0, 0, 1, 0, 0, 0];
double[] perClass = FBeta.PerClass(yTrue, yPred, 2.0);
double ham = perClass[0]; // => 0.7142…
double spam = perClass[1]; // => 0.5263…Remarks — the per-class form exists for the same reason F1.PerClass does: to see which class
a
macro average is hiding. It is worth a moment's thought before using it, though, because beta
weights recall over precision for every class at once, and the asymmetry that justified beta
was usually about one class in particular.
The trap is the arithmetic behind the scenes rather than in the result. beta is applied by
substituting the true positives, the predicted count and the support algebraically rather than by
computing precision and recall and combining them, which is what keeps the answer exact at the
edges where one of the two is undefined: (1 + β²)·tp / (predicted + β²·support) has no
precision or recall in it to be undefined, so only its own denominator can be zero. Nothing about the call changes; it is the reason the undefined cases here agree
with
scikit-learn rather than approximately agreeing.
Applies to — net10.0, netstandard2.0.
See also — FBeta.Score, F1.PerClass, ClassificationReport.Compute,
the Python equivalence table.