如何在assertDictEqual中引入relative/absolute容忍度?
How to introduce relative/absolute tolerance in assertDictEqual?
是否有内置方法,或者是否有一种快速有效的方法让 assertDictEqual()
具有与 rtol
and/or atol
相同的功能对于 asset_frame_equal()
在 pandas.testing
?
我希望能够比较两个字典中对应于同一个键的值是否相等,当值在给定的公差限制内彼此接近时,它们作为相等传递。类似于 atol/rtol 对 frame_equal 的作用。
MRE:
import numpy as np
def assert_dicts_almost_equal(d1, d2, rtol=0.01, atol=0.1):
assert len(d1) == len(d2), 'Unequal number of elements.'
for key in d1:
try:
np.testing.assert_allclose(d1[key], d2[key], rtol=rtol, atol=atol)
except AssertionError as msg:
print('Assertion Error for {key}'.format(key=key))
print(msg)
数据:
d = {'A': 0.49, 'B': 0.51}
d0 = {'A': 0.4999999999999991, 'B': 0.5000000000000007, 'C': np.nan}
d1 = {'A': 0.3105572709904508, 'B': 0.5030302993151613, 'C': np.nan}
d2 = {'A': 0.4813463081397519, 'B': 0.5104397084554964, 'C': np.nan}
d3 = {'A': 0.4740668937066489, 'B': 0.5144020381674881, 'C': np.nan}
测试:
assert_dicts_almost_equal(d0, d)
assert_dicts_almost_equal(d0, d1)
assert_dicts_almost_equal(d0, d2)
assert_dicts_almost_equal(d0, d3)
只有前两个会引发断言错误,其余的都会通过。
Numpy 的 assert_allclose 类似。这是演示的玩具示例。
import numpy as np
dict_a = {'A': np.array([1,2,3]), 'B': np.array([4,5,6]), 'C': np.array([7,8,9])}
dict_b = {'A': np.array([1,2,3]), 'B': np.array([4,5,20]), 'C': np.array([7,8,9])}
for k, v in dict_a.items():
try:
np.testing.assert_allclose(dict_a[k], dict_b[k], atol=2)
print('{k} is close'.format(k=k))
except AssertionError as msg:
print('Assertion Error for {k}'.format(k=k))
print(msg)
输出:
A is close
Assertion Error for B
Not equal to tolerance rtol=1e-07, atol=2
Mismatched elements: 1 / 3 (33.3%)
Max absolute difference: 14
Max relative difference: 0.7
x: array([4, 5, 6])
y: array([ 4, 5, 20])
C is close
在此示例中,atol 参数设置为更高的 25,其 B 值在绝对公差范围内。
import numpy as np
dict_a = {'A': np.array([1,2,3]), 'B': np.array([4,5,6]), 'C': np.array([7,8,9])}
dict_b = {'A': np.array([1,2,3]), 'B': np.array([4,5,20]), 'C': np.array([7,8,9])}
for k, v in dict_a.items():
try:
np.testing.assert_allclose(dict_a[k], dict_b[k], atol=25)
print('{k} is close'.format(k=k))
except AssertionError as msg:
print('Assertion Error for {k}'.format(k=k))
print(msg)
输出:
A is close
B is close
C is close
编辑评论:
我根据您的评论对此进行了一些更改。现在原始字典是列表和单个值的混合,数组转换发生在循环中。 Numpy 更灵活,因为与无法处理列表的 math.isclose() 相比,它可以处理列表或单个值。
import numpy as np
import math
dict_a = {'A': [1,2,3], 'B': [1,2,3], 'C': [1,2,3]}
dict_b = {'A': [1,2,3], 'B': 66, 'C': [1,2,3]}
for k, v in dict_a.items():
try:
np.testing.assert_allclose(np.array(dict_a[k]), np.array(dict_b[k]), atol=25)
#math.isclose(dict_a[k], dict_b[k])
print('{k} is close'.format(k=k))
except AssertionError as msg:
print('Assertion Error for {k}'.format(k=k))
print(msg)
输出:
A is close
Assertion Error for B
Not equal to tolerance rtol=1e-07, atol=25
Mismatched elements: 3 / 3 (100%)
Max absolute difference: 65
Max relative difference: 0.98484848
x: array([1, 2, 3])
y: array(66)
C is close
是否有内置方法,或者是否有一种快速有效的方法让 assertDictEqual()
具有与 rtol
and/or atol
相同的功能对于 asset_frame_equal()
在 pandas.testing
?
我希望能够比较两个字典中对应于同一个键的值是否相等,当值在给定的公差限制内彼此接近时,它们作为相等传递。类似于 atol/rtol 对 frame_equal 的作用。
MRE:
import numpy as np
def assert_dicts_almost_equal(d1, d2, rtol=0.01, atol=0.1):
assert len(d1) == len(d2), 'Unequal number of elements.'
for key in d1:
try:
np.testing.assert_allclose(d1[key], d2[key], rtol=rtol, atol=atol)
except AssertionError as msg:
print('Assertion Error for {key}'.format(key=key))
print(msg)
数据:
d = {'A': 0.49, 'B': 0.51}
d0 = {'A': 0.4999999999999991, 'B': 0.5000000000000007, 'C': np.nan}
d1 = {'A': 0.3105572709904508, 'B': 0.5030302993151613, 'C': np.nan}
d2 = {'A': 0.4813463081397519, 'B': 0.5104397084554964, 'C': np.nan}
d3 = {'A': 0.4740668937066489, 'B': 0.5144020381674881, 'C': np.nan}
测试:
assert_dicts_almost_equal(d0, d)
assert_dicts_almost_equal(d0, d1)
assert_dicts_almost_equal(d0, d2)
assert_dicts_almost_equal(d0, d3)
只有前两个会引发断言错误,其余的都会通过。
Numpy 的 assert_allclose 类似。这是演示的玩具示例。
import numpy as np
dict_a = {'A': np.array([1,2,3]), 'B': np.array([4,5,6]), 'C': np.array([7,8,9])}
dict_b = {'A': np.array([1,2,3]), 'B': np.array([4,5,20]), 'C': np.array([7,8,9])}
for k, v in dict_a.items():
try:
np.testing.assert_allclose(dict_a[k], dict_b[k], atol=2)
print('{k} is close'.format(k=k))
except AssertionError as msg:
print('Assertion Error for {k}'.format(k=k))
print(msg)
输出:
A is close
Assertion Error for B
Not equal to tolerance rtol=1e-07, atol=2
Mismatched elements: 1 / 3 (33.3%)
Max absolute difference: 14
Max relative difference: 0.7
x: array([4, 5, 6])
y: array([ 4, 5, 20])
C is close
在此示例中,atol 参数设置为更高的 25,其 B 值在绝对公差范围内。
import numpy as np
dict_a = {'A': np.array([1,2,3]), 'B': np.array([4,5,6]), 'C': np.array([7,8,9])}
dict_b = {'A': np.array([1,2,3]), 'B': np.array([4,5,20]), 'C': np.array([7,8,9])}
for k, v in dict_a.items():
try:
np.testing.assert_allclose(dict_a[k], dict_b[k], atol=25)
print('{k} is close'.format(k=k))
except AssertionError as msg:
print('Assertion Error for {k}'.format(k=k))
print(msg)
输出:
A is close
B is close
C is close
编辑评论:
我根据您的评论对此进行了一些更改。现在原始字典是列表和单个值的混合,数组转换发生在循环中。 Numpy 更灵活,因为与无法处理列表的 math.isclose() 相比,它可以处理列表或单个值。
import numpy as np
import math
dict_a = {'A': [1,2,3], 'B': [1,2,3], 'C': [1,2,3]}
dict_b = {'A': [1,2,3], 'B': 66, 'C': [1,2,3]}
for k, v in dict_a.items():
try:
np.testing.assert_allclose(np.array(dict_a[k]), np.array(dict_b[k]), atol=25)
#math.isclose(dict_a[k], dict_b[k])
print('{k} is close'.format(k=k))
except AssertionError as msg:
print('Assertion Error for {k}'.format(k=k))
print(msg)
输出:
A is close
Assertion Error for B
Not equal to tolerance rtol=1e-07, atol=25
Mismatched elements: 3 / 3 (100%)
Max absolute difference: 65
Max relative difference: 0.98484848
x: array([1, 2, 3])
y: array(66)
C is close