Skip to content

Fix TypeError in macro f1 when zero_division=0.0 - #168

Open
JayeshSuryavanshi wants to merge 1 commit into
scikit-learn-contrib:mainfrom
JayeshSuryavanshi:fix/f1-macro-zero-division-0
Open

Fix TypeError in macro f1 when zero_division=0.0#168
JayeshSuryavanshi wants to merge 1 commit into
scikit-learn-contrib:mainfrom
JayeshSuryavanshi:fix/f1-macro-zero-division-0

Conversation

@JayeshSuryavanshi

Copy link
Copy Markdown

Problem

f1(y_true, y_pred, average="macro", zero_division=0.0) raises:

TypeError: _f_score_micro() missing 1 required positional argument: 'zero_division'

0.0 is a documented, valid value for zero_division (the docstring lists {"warn", 0.0, 1.0, np.nan}), so this should work the same as the other options.

Root cause

In _compute_macro, the per-sample dispatch guards with a truthiness check:

for ground_truth, prediction in zip(y_true, y_pred):
    if zero_division:
        sample_score = _micro_function(np.array([ground_truth]), np.array([prediction]), zero_division)
    else:
        sample_score = _micro_function(np.array([ground_truth]), np.array([prediction]))

The intent of that branch is "if the micro function accepts a zero_division argument, forward it." precision/recall macro leave the argument at its None default and correctly take the 2-argument path. But the f-score path always passes a value, and 0.0 (and 0) is falsy, so it wrongly falls through to the 2-argument call, and _f_score_micro requires the third argument. The other documented values ("warn", 1.0, np.nan) are all truthy, which is why this went unnoticed.

Fix

Guard on is not None instead of truthiness:

if zero_division is not None:

precision/recall macro still take the None default path; the f-score path now forwards 0.0 correctly. No other behavior changes.

Tests

The existing macro tests exercised zero_division via the default "warn", plus 1.0 and np.nan, but never the explicit 0.0, which is exactly the gap that let this ship. Added assert 0.0 == f1(y_true, y_pred, "macro", 0.0) to all five macro f1 tests (1d/2d/3d, list and array).

Verified: reproduced the TypeError before the change, confirmed it is gone after, confirmed explicit 0.0 returns 0.0 with no spurious warning, and confirmed precision/recall macro are unaffected. Full tests/test_metrics.py passes (63/63).

Closes #161

_compute_macro dispatched with `if zero_division:`, which is falsy for the
valid, documented value 0.0 (and 0), so it called _f_score_micro without the
required zero_division argument and raised TypeError. The other documented
values ("warn", 1.0, np.nan) are truthy, which is why it went unnoticed.

Guard on `if zero_division is not None:` instead; precision and recall macro
keep the None default path. Added explicit zero_division=0.0 coverage to all
five macro f1 tests.
@JayeshSuryavanshi

Copy link
Copy Markdown
Author

Note on the failing docs/readthedocs.org check: it's the docs build, not the test suite, and it appears pre-existing rather than caused by this PR. This change only touches metrics.py (one line) and the metrics tests, nothing docs-related. I ran the Sphinx gallery examples locally on this branch and they execute fine except the ray-based plot_parallel_training.py (which downloads a dataset), which looks like the flaky cause; the same check also fails on some unrelated PRs. Separately, while checking this I found and fixed a genuine numpy 2.5 incompatibility (np.cross on 2-D vectors in the Venn-Abers calibrator) in #170.

@JayeshSuryavanshi

Copy link
Copy Markdown
Author

Hi @mirand863, I have three small fixes open here, would you have time to look?

The red readthedocs check on all three is the docs build rather than the test suite, and it fails the same way on PRs that aren't mine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Exception when computing f1 metrics with average='macro' and zero_division=0.0

1 participant