-
Notifications
You must be signed in to change notification settings - Fork 168
feat: Add {Expr,Series}.is_close
#2962
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 14 commits
02a746e
69907eb
fd4a3cf
7be5176
1df7bf2
0b4de26
c6ce52c
89c947b
a271a94
e59d8e7
148c8bc
ad9be73
4756371
cf8f83d
6bb54e9
22e2203
dccd612
0dfaf5a
8a1cb13
df24a41
5838826
602fa29
e4b7a1e
d61c5c7
8d3532f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,7 @@ | |
| - filter | ||
| - clip | ||
| - is_between | ||
| - is_close | ||
| - is_duplicated | ||
| - is_finite | ||
| - is_first_distinct | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,7 @@ | |
| - hist | ||
| - implementation | ||
| - is_between | ||
| - is_close | ||
| - is_duplicated | ||
| - is_empty | ||
| - is_finite | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -72,7 +72,7 @@ | |
| NativeFrameT_co, | ||
| NativeSeriesT_co, | ||
| ) | ||
| from narwhals._compliant.typing import EvalNames | ||
| from narwhals._compliant.typing import CompliantSeriesOrExprT, EvalNames | ||
| from narwhals._namespace import EagerAllowedImplementation, Namespace | ||
| from narwhals._translate import ArrowStreamExportable, IntoArrowTable, ToNarwhalsT_co | ||
| from narwhals.dataframe import DataFrame, LazyFrame | ||
|
|
@@ -86,6 +86,7 @@ | |
| DTypes, | ||
| IntoSeriesT, | ||
| MultiIndexSelector, | ||
| NumericLiteral, | ||
| SingleIndexSelector, | ||
| SizedMultiIndexSelector, | ||
| SizeUnit, | ||
|
|
@@ -2035,3 +2036,62 @@ def deep_attrgetter(attr: str, *nested: str) -> attrgetter[Any]: | |
| def deep_getattr(obj: Any, name_1: str, *nested: str) -> Any: | ||
| """Perform a nested attribute lookup on `obj`.""" | ||
| return deep_attrgetter(name_1, *nested)(obj) | ||
|
|
||
|
|
||
| def _is_close_impl( | ||
|
||
| self: CompliantSeriesOrExprT, | ||
| other: CompliantSeriesOrExprT | NumericLiteral, | ||
| *, | ||
| abs_tol: float, | ||
| rel_tol: float, | ||
| nans_equal: bool, | ||
| ) -> CompliantSeriesOrExprT: | ||
| from decimal import Decimal | ||
|
|
||
| other_abs: CompliantSeriesOrExprT | NumericLiteral | ||
| other_is_nan: CompliantSeriesOrExprT | bool | ||
| other_is_inf: CompliantSeriesOrExprT | bool | ||
| other_is_not_inf: CompliantSeriesOrExprT | bool | ||
|
|
||
| if isinstance(other, (float, int, Decimal)): | ||
| from math import isinf, isnan | ||
|
|
||
| other_abs, other_is_nan, other_is_inf = abs(other), isnan(other), isinf(other) # type: ignore[assignment] | ||
|
|
||
| # Define the other_is_not_inf variable to prevent triggering the following warning: | ||
| # > DeprecationWarning: Bitwise inversion '~' on bool is deprecated and will be | ||
| # > removed in Python 3.16. This returns the bitwise inversion of the | ||
| # > underlying int object and is usually not what you expect from negating | ||
| # > a bool. Use the 'not' operator for boolean negation or ~int(x) if you | ||
| # > really want the bitwise inversion of the underlying int. | ||
| other_is_not_inf = not other_is_inf | ||
|
|
||
| else: | ||
| other_abs, other_is_nan = other.abs(), other.is_nan() | ||
| other_is_not_inf = other.is_finite() | other_is_nan | ||
| other_is_inf = ~other_is_not_inf | ||
|
|
||
| rel_threshold = self.abs().clip(lower_bound=other_abs, upper_bound=None) * rel_tol # type: ignore[arg-type] | ||
| tolerance = rel_threshold.clip(lower_bound=abs_tol, upper_bound=None) | ||
|
|
||
| self_is_nan = self.is_nan() | ||
| self_is_not_inf = self.is_finite() | self_is_nan | ||
|
|
||
| # Values are close if abs_diff <= tolerance, and both finite | ||
| is_close = ((self - other).abs() <= tolerance) & self_is_not_inf & other_is_not_inf | ||
|
|
||
| # Handle infinity cases: infinities are "close" only if they have the same sign | ||
| self_sign, other_sign = self > 0, other > 0 | ||
| is_same_inf = (~self_is_not_inf) & other_is_inf & (self_sign == other_sign) | ||
|
|
||
| # Handle nan cases: | ||
| # * nans_equals = True => if both values are NaN, then True | ||
| # * nans_equals = False => if any value is NaN, then False | ||
| either_nan = self_is_nan | other_is_nan | ||
| result = (is_close | is_same_inf) & ~either_nan | ||
|
|
||
| if nans_equal: | ||
| both_nan = self_is_nan & other_is_nan | ||
| result = result | both_nan | ||
|
|
||
| return result | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might not be needed π€