Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Allow absolute precision in assert_almost_equal (#13357) #30562

Merged
merged 1 commit into from
Jun 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/source/whatsnew/v1.1.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,9 @@ Deprecations
- The ``squeeze`` keyword in the ``groupby`` function is deprecated and will be removed in a future version (:issue:`32380`)
- The ``tz`` keyword in :meth:`Period.to_timestamp` is deprecated and will be removed in a future version; use `per.to_timestamp(...).tz_localize(tz)`` instead (:issue:`34522`)
- :meth:`DatetimeIndex.to_perioddelta` is deprecated and will be removed in a future version. Use ``index - index.to_period(freq).to_timestamp()`` instead (:issue:`34853`)
- :meth:`util.testing.assert_almost_equal` now accepts both relative and absolute
precision through the ``rtol``, and ``atol`` parameters, thus deprecating the
``check_less_precise`` parameter. (:issue:`13357`).
Copy link
Contributor

Choose a reason for hiding this comment

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

can you also indicate #9457 here (for a followon PR is fine)


.. ---------------------------------------------------------------------------

Expand Down
58 changes: 20 additions & 38 deletions pandas/_libs/testing.pyx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import math

import numpy as np
from numpy cimport import_array
import_array()
Expand Down Expand Up @@ -42,12 +44,6 @@ cdef bint is_dictlike(obj):
return hasattr(obj, 'keys') and hasattr(obj, '__getitem__')


cdef bint decimal_almost_equal(double desired, double actual, int decimal):
# Code from
# https://numpy.org/doc/stable/reference/generated/numpy.testing.assert_almost_equal.html
return abs(desired - actual) < (0.5 * 10.0 ** -decimal)


cpdef assert_dict_equal(a, b, bint compare_keys=True):
assert is_dictlike(a) and is_dictlike(b), (
"Cannot compare dict objects, one or both is not dict-like"
Expand All @@ -66,7 +62,7 @@ cpdef assert_dict_equal(a, b, bint compare_keys=True):


cpdef assert_almost_equal(a, b,
check_less_precise=False,
rtol=1.e-5, atol=1.e-8,
bint check_dtype=True,
obj=None, lobj=None, robj=None, index_values=None):
"""
Expand All @@ -76,31 +72,33 @@ cpdef assert_almost_equal(a, b,
----------
a : object
b : object
check_less_precise : bool or int, default False
joaoleveiga marked this conversation as resolved.
Show resolved Hide resolved
Specify comparison precision.
5 digits (False) or 3 digits (True) after decimal points are
compared. If an integer, then this will be the number of decimal
points to compare
rtol : float, default 1e-5
Relative tolerance.

.. versionadded:: 1.1.0
atol : float, default 1e-8
joaoleveiga marked this conversation as resolved.
Show resolved Hide resolved
Absolute tolerance.

.. versionadded:: 1.1.0
check_dtype: bool, default True
check dtype if both a and b are np.ndarray
check dtype if both a and b are np.ndarray.
obj : str, default None
Specify object name being compared, internally used to show
appropriate assertion message
appropriate assertion message.
lobj : str, default None
Specify left object name being compared, internally used to show
appropriate assertion message
appropriate assertion message.
robj : str, default None
Specify right object name being compared, internally used to show
appropriate assertion message
appropriate assertion message.
index_values : ndarray, default None
Specify shared index values of objects being compared, internally used
to show appropriate assertion message
to show appropriate assertion message.

.. versionadded:: 1.1.0

"""
cdef:
int decimal
double diff = 0.0
Py_ssize_t i, na, nb
double fa, fb
Expand All @@ -111,8 +109,6 @@ cpdef assert_almost_equal(a, b,
if robj is None:
robj = b

assert isinstance(check_less_precise, (int, bool))

if isinstance(a, dict) or isinstance(b, dict):
return assert_dict_equal(a, b)

Expand Down Expand Up @@ -170,8 +166,7 @@ cpdef assert_almost_equal(a, b,

for i in range(len(a)):
try:
assert_almost_equal(a[i], b[i],
check_less_precise=check_less_precise)
assert_almost_equal(a[i], b[i], rtol=rtol, atol=atol)
except AssertionError:
is_unequal = True
diff += 1
Expand Down Expand Up @@ -203,24 +198,11 @@ cpdef assert_almost_equal(a, b,
# inf comparison
return True

if check_less_precise is True:
decimal = 3
elif check_less_precise is False:
decimal = 5
else:
decimal = check_less_precise

fa, fb = a, b

# case for zero
if abs(fa) < 1e-5:
if not decimal_almost_equal(fa, fb, decimal):
assert False, (f'(very low values) expected {fb:.5f} '
f'but got {fa:.5f}, with decimal {decimal}')
else:
if not decimal_almost_equal(1, fb / fa, decimal):
assert False, (f'expected {fb:.5f} but got {fa:.5f}, '
f'with decimal {decimal}')
if not math.isclose(fa, fb, rel_tol=rtol, abs_tol=atol):
jreback marked this conversation as resolved.
Show resolved Hide resolved
assert False, (f"expected {fb:.5f} but got {fa:.5f}, "
f"with rtol={rtol}, atol={atol}")
return True

raise AssertionError(f"{a} != {b}")