Skip to content

Add a ThresholdFilterCodec that replaces values whose magnitude is below a threshold - #5

Open
SF-N wants to merge 1 commit into
juntyr:mainfrom
SF-N:threshold-filter
Open

SF-N wants to merge 1 commit into
juntyr:mainfrom
SF-N:threshold-filter

Conversation

@SF-N

@SF-N SF-N commented Sep 30, 2026

Copy link
Copy Markdown

Summary

Adds ThresholdFilterCodec (id replace.threshold), a filter codec in the style of ReplaceFilterCodec: during encoding all values with |x| < threshold are replaced by replacement (zero by default; the special Replacement values such as finite_max are supported and computed before the replacement), NaN values are never replaced; decoding passes the data through.

  • ReplaceFilterCodec is unchanged
  • entry point replace.threshold, tests (configuration/repr, float/int/inf/NaN cases, finite_max replacement, integer data), README line

Motivation

Under a mean error bound, spending a part of the budget on setting the smallest values of a heavy-tailed field to zero (which can then be masked by MaskMetaCodec and skipped by the subsequent codecs) improves the compression ratio considerably, e.g. surface runoff in the compression lab challenges 209 -> 232. This codec expresses that step as a reusable, stackable filter.


class ThresholdFilterCodec(Codec):
"""
Filter codec that replaces all values whose magnitude is below a

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we support replacing values below and values above the threshold? Some encodings of missing data use huge values, and so replacing only large magnitudes would also be very useful

_threshold: int | float
_replacement: int | float | Replacement

codec_id: str = "replace.threshold" # type: ignore

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a huge fan but don't have a better idea :)

"nan_min",
"nan_mean",
"nan_max",
] = 0,

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a replace |x| < t, a default of zero is ok, but if we generalise I'd prefer to not offer a default at all and just always be explicit

"nan_max",
] = 0,
) -> None:
if not (threshold >= 0):

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also check that the threshold is finite (I guess an infinite threshold would also be fun, but it should definitely not be NaN)

"nan_max",
] = 0,
) -> None:
if not (threshold >= 0):

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we use |x| < t, then a threshold of zero is useless since it doesn't apply. I think it would be better to add an option for either being inclusive (<=) or exclusive (<)

else self._replacement
)

with np.errstate(invalid="ignore"):

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't ignore this in the other codec, why here?

Comment thread tests/test_replace.py
assert codec.get_config() == dict(
id="replace.threshold", threshold=1e-3, replacement=0.0
)
with pytest.raises(ValueError):

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also check the message against a regex

Comment thread README.md
# numcodecs-replace

Value replacement codecs for the [`numcodecs`] buffer compression API.
Value replacement codecs for the [`numcodecs`] buffer compression API: `ReplaceFilterCodec` replaces configured values, `ThresholdFilterCodec` replaces all values whose magnitude is below a threshold (e.g. to drop negligible values before lossy compression).

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs/index.md should also be changed, and there you can doc-reference the actual classes so that they become clickable links, e.g.

[`ReplaceFilterCodec`][numcodecs_replace.ReplaceFilterCodec]

This branch has not been deployed

No deployments
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.

2 participants