test_assert_almost_equal.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. import numpy as np
  2. import pytest
  3. from pandas import (
  4. DataFrame,
  5. Index,
  6. Series,
  7. Timestamp,
  8. )
  9. import pandas._testing as tm
  10. def _assert_almost_equal_both(a, b, **kwargs):
  11. """
  12. Check that two objects are approximately equal.
  13. This check is performed commutatively.
  14. Parameters
  15. ----------
  16. a : object
  17. The first object to compare.
  18. b : object
  19. The second object to compare.
  20. **kwargs
  21. The arguments passed to `tm.assert_almost_equal`.
  22. """
  23. tm.assert_almost_equal(a, b, **kwargs)
  24. tm.assert_almost_equal(b, a, **kwargs)
  25. def _assert_not_almost_equal(a, b, **kwargs):
  26. """
  27. Check that two objects are not approximately equal.
  28. Parameters
  29. ----------
  30. a : object
  31. The first object to compare.
  32. b : object
  33. The second object to compare.
  34. **kwargs
  35. The arguments passed to `tm.assert_almost_equal`.
  36. """
  37. try:
  38. tm.assert_almost_equal(a, b, **kwargs)
  39. msg = f"{a} and {b} were approximately equal when they shouldn't have been"
  40. pytest.fail(msg=msg)
  41. except AssertionError:
  42. pass
  43. def _assert_not_almost_equal_both(a, b, **kwargs):
  44. """
  45. Check that two objects are not approximately equal.
  46. This check is performed commutatively.
  47. Parameters
  48. ----------
  49. a : object
  50. The first object to compare.
  51. b : object
  52. The second object to compare.
  53. **kwargs
  54. The arguments passed to `tm.assert_almost_equal`.
  55. """
  56. _assert_not_almost_equal(a, b, **kwargs)
  57. _assert_not_almost_equal(b, a, **kwargs)
  58. @pytest.mark.parametrize(
  59. "a,b",
  60. [
  61. (1.1, 1.1),
  62. (1.1, 1.100001),
  63. (np.int16(1), 1.000001),
  64. (np.float64(1.1), 1.1),
  65. (np.uint32(5), 5),
  66. ],
  67. )
  68. def test_assert_almost_equal_numbers(a, b):
  69. _assert_almost_equal_both(a, b)
  70. @pytest.mark.parametrize(
  71. "a,b",
  72. [
  73. (1.1, 1),
  74. (1.1, True),
  75. (1, 2),
  76. (1.0001, np.int16(1)),
  77. # The following two examples are not "almost equal" due to tol.
  78. (0.1, 0.1001),
  79. (0.0011, 0.0012),
  80. ],
  81. )
  82. def test_assert_not_almost_equal_numbers(a, b):
  83. _assert_not_almost_equal_both(a, b)
  84. @pytest.mark.parametrize(
  85. "a,b",
  86. [
  87. (1.1, 1.1),
  88. (1.1, 1.100001),
  89. (1.1, 1.1001),
  90. (0.000001, 0.000005),
  91. (1000.0, 1000.0005),
  92. # Testing this example, as per #13357
  93. (0.000011, 0.000012),
  94. ],
  95. )
  96. def test_assert_almost_equal_numbers_atol(a, b):
  97. # Equivalent to the deprecated check_less_precise=True, enforced in 2.0
  98. _assert_almost_equal_both(a, b, rtol=0.5e-3, atol=0.5e-3)
  99. @pytest.mark.parametrize("a,b", [(1.1, 1.11), (0.1, 0.101), (0.000011, 0.001012)])
  100. def test_assert_not_almost_equal_numbers_atol(a, b):
  101. _assert_not_almost_equal_both(a, b, atol=1e-3)
  102. @pytest.mark.parametrize(
  103. "a,b",
  104. [
  105. (1.1, 1.1),
  106. (1.1, 1.100001),
  107. (1.1, 1.1001),
  108. (1000.0, 1000.0005),
  109. (1.1, 1.11),
  110. (0.1, 0.101),
  111. ],
  112. )
  113. def test_assert_almost_equal_numbers_rtol(a, b):
  114. _assert_almost_equal_both(a, b, rtol=0.05)
  115. @pytest.mark.parametrize("a,b", [(0.000011, 0.000012), (0.000001, 0.000005)])
  116. def test_assert_not_almost_equal_numbers_rtol(a, b):
  117. _assert_not_almost_equal_both(a, b, rtol=0.05)
  118. @pytest.mark.parametrize(
  119. "a,b,rtol",
  120. [
  121. (1.00001, 1.00005, 0.001),
  122. (-0.908356 + 0.2j, -0.908358 + 0.2j, 1e-3),
  123. (0.1 + 1.009j, 0.1 + 1.006j, 0.1),
  124. (0.1001 + 2.0j, 0.1 + 2.001j, 0.01),
  125. ],
  126. )
  127. def test_assert_almost_equal_complex_numbers(a, b, rtol):
  128. _assert_almost_equal_both(a, b, rtol=rtol)
  129. _assert_almost_equal_both(np.complex64(a), np.complex64(b), rtol=rtol)
  130. _assert_almost_equal_both(np.complex128(a), np.complex128(b), rtol=rtol)
  131. @pytest.mark.parametrize(
  132. "a,b,rtol",
  133. [
  134. (0.58310768, 0.58330768, 1e-7),
  135. (-0.908 + 0.2j, -0.978 + 0.2j, 0.001),
  136. (0.1 + 1j, 0.1 + 2j, 0.01),
  137. (-0.132 + 1.001j, -0.132 + 1.005j, 1e-5),
  138. (0.58310768j, 0.58330768j, 1e-9),
  139. ],
  140. )
  141. def test_assert_not_almost_equal_complex_numbers(a, b, rtol):
  142. _assert_not_almost_equal_both(a, b, rtol=rtol)
  143. _assert_not_almost_equal_both(np.complex64(a), np.complex64(b), rtol=rtol)
  144. _assert_not_almost_equal_both(np.complex128(a), np.complex128(b), rtol=rtol)
  145. @pytest.mark.parametrize("a,b", [(0, 0), (0, 0.0), (0, np.float64(0)), (0.00000001, 0)])
  146. def test_assert_almost_equal_numbers_with_zeros(a, b):
  147. _assert_almost_equal_both(a, b)
  148. @pytest.mark.parametrize("a,b", [(0.001, 0), (1, 0)])
  149. def test_assert_not_almost_equal_numbers_with_zeros(a, b):
  150. _assert_not_almost_equal_both(a, b)
  151. @pytest.mark.parametrize("a,b", [(1, "abc"), (1, [1]), (1, object())])
  152. def test_assert_not_almost_equal_numbers_with_mixed(a, b):
  153. _assert_not_almost_equal_both(a, b)
  154. @pytest.mark.parametrize(
  155. "left_dtype", ["M8[ns]", "m8[ns]", "float64", "int64", "object"]
  156. )
  157. @pytest.mark.parametrize(
  158. "right_dtype", ["M8[ns]", "m8[ns]", "float64", "int64", "object"]
  159. )
  160. def test_assert_almost_equal_edge_case_ndarrays(left_dtype, right_dtype):
  161. # Empty compare.
  162. _assert_almost_equal_both(
  163. np.array([], dtype=left_dtype),
  164. np.array([], dtype=right_dtype),
  165. check_dtype=False,
  166. )
  167. def test_assert_almost_equal_dicts():
  168. _assert_almost_equal_both({"a": 1, "b": 2}, {"a": 1, "b": 2})
  169. @pytest.mark.parametrize(
  170. "a,b",
  171. [
  172. ({"a": 1, "b": 2}, {"a": 1, "b": 3}),
  173. ({"a": 1, "b": 2}, {"a": 1, "b": 2, "c": 3}),
  174. ({"a": 1}, 1),
  175. ({"a": 1}, "abc"),
  176. ({"a": 1}, [1]),
  177. ],
  178. )
  179. def test_assert_not_almost_equal_dicts(a, b):
  180. _assert_not_almost_equal_both(a, b)
  181. @pytest.mark.parametrize("val", [1, 2])
  182. def test_assert_almost_equal_dict_like_object(val):
  183. dict_val = 1
  184. real_dict = {"a": val}
  185. class DictLikeObj:
  186. def keys(self):
  187. return ("a",)
  188. def __getitem__(self, item):
  189. if item == "a":
  190. return dict_val
  191. func = (
  192. _assert_almost_equal_both if val == dict_val else _assert_not_almost_equal_both
  193. )
  194. func(real_dict, DictLikeObj(), check_dtype=False)
  195. def test_assert_almost_equal_strings():
  196. _assert_almost_equal_both("abc", "abc")
  197. @pytest.mark.parametrize(
  198. "a,b", [("abc", "abcd"), ("abc", "abd"), ("abc", 1), ("abc", [1])]
  199. )
  200. def test_assert_not_almost_equal_strings(a, b):
  201. _assert_not_almost_equal_both(a, b)
  202. @pytest.mark.parametrize(
  203. "a,b", [([1, 2, 3], [1, 2, 3]), (np.array([1, 2, 3]), np.array([1, 2, 3]))]
  204. )
  205. def test_assert_almost_equal_iterables(a, b):
  206. _assert_almost_equal_both(a, b)
  207. @pytest.mark.parametrize(
  208. "a,b",
  209. [
  210. # Class is different.
  211. (np.array([1, 2, 3]), [1, 2, 3]),
  212. # Dtype is different.
  213. (np.array([1, 2, 3]), np.array([1.0, 2.0, 3.0])),
  214. # Can't compare generators.
  215. (iter([1, 2, 3]), [1, 2, 3]),
  216. ([1, 2, 3], [1, 2, 4]),
  217. ([1, 2, 3], [1, 2, 3, 4]),
  218. ([1, 2, 3], 1),
  219. ],
  220. )
  221. def test_assert_not_almost_equal_iterables(a, b):
  222. _assert_not_almost_equal(a, b)
  223. def test_assert_almost_equal_null():
  224. _assert_almost_equal_both(None, None)
  225. @pytest.mark.parametrize("a,b", [(None, np.NaN), (None, 0), (np.NaN, 0)])
  226. def test_assert_not_almost_equal_null(a, b):
  227. _assert_not_almost_equal(a, b)
  228. @pytest.mark.parametrize(
  229. "a,b",
  230. [
  231. (np.inf, np.inf),
  232. (np.inf, float("inf")),
  233. (np.array([np.inf, np.nan, -np.inf]), np.array([np.inf, np.nan, -np.inf])),
  234. (
  235. np.array([np.inf, None, -np.inf], dtype=np.object_),
  236. np.array([np.inf, np.nan, -np.inf], dtype=np.object_),
  237. ),
  238. ],
  239. )
  240. def test_assert_almost_equal_inf(a, b):
  241. _assert_almost_equal_both(a, b)
  242. def test_assert_not_almost_equal_inf():
  243. _assert_not_almost_equal_both(np.inf, 0)
  244. @pytest.mark.parametrize(
  245. "a,b",
  246. [
  247. (Index([1.0, 1.1]), Index([1.0, 1.100001])),
  248. (Series([1.0, 1.1]), Series([1.0, 1.100001])),
  249. (np.array([1.1, 2.000001]), np.array([1.1, 2.0])),
  250. (DataFrame({"a": [1.0, 1.1]}), DataFrame({"a": [1.0, 1.100001]})),
  251. ],
  252. )
  253. def test_assert_almost_equal_pandas(a, b):
  254. _assert_almost_equal_both(a, b)
  255. def test_assert_almost_equal_object():
  256. a = [Timestamp("2011-01-01"), Timestamp("2011-01-01")]
  257. b = [Timestamp("2011-01-01"), Timestamp("2011-01-01")]
  258. _assert_almost_equal_both(a, b)
  259. def test_assert_almost_equal_value_mismatch():
  260. msg = "expected 2\\.00000 but got 1\\.00000, with rtol=1e-05, atol=1e-08"
  261. with pytest.raises(AssertionError, match=msg):
  262. tm.assert_almost_equal(1, 2)
  263. @pytest.mark.parametrize(
  264. "a,b,klass1,klass2",
  265. [(np.array([1]), 1, "ndarray", "int"), (1, np.array([1]), "int", "ndarray")],
  266. )
  267. def test_assert_almost_equal_class_mismatch(a, b, klass1, klass2):
  268. msg = f"""numpy array are different
  269. numpy array classes are different
  270. \\[left\\]: {klass1}
  271. \\[right\\]: {klass2}"""
  272. with pytest.raises(AssertionError, match=msg):
  273. tm.assert_almost_equal(a, b)
  274. def test_assert_almost_equal_value_mismatch1():
  275. msg = """numpy array are different
  276. numpy array values are different \\(66\\.66667 %\\)
  277. \\[left\\]: \\[nan, 2\\.0, 3\\.0\\]
  278. \\[right\\]: \\[1\\.0, nan, 3\\.0\\]"""
  279. with pytest.raises(AssertionError, match=msg):
  280. tm.assert_almost_equal(np.array([np.nan, 2, 3]), np.array([1, np.nan, 3]))
  281. def test_assert_almost_equal_value_mismatch2():
  282. msg = """numpy array are different
  283. numpy array values are different \\(50\\.0 %\\)
  284. \\[left\\]: \\[1, 2\\]
  285. \\[right\\]: \\[1, 3\\]"""
  286. with pytest.raises(AssertionError, match=msg):
  287. tm.assert_almost_equal(np.array([1, 2]), np.array([1, 3]))
  288. def test_assert_almost_equal_value_mismatch3():
  289. msg = """numpy array are different
  290. numpy array values are different \\(16\\.66667 %\\)
  291. \\[left\\]: \\[\\[1, 2\\], \\[3, 4\\], \\[5, 6\\]\\]
  292. \\[right\\]: \\[\\[1, 3\\], \\[3, 4\\], \\[5, 6\\]\\]"""
  293. with pytest.raises(AssertionError, match=msg):
  294. tm.assert_almost_equal(
  295. np.array([[1, 2], [3, 4], [5, 6]]), np.array([[1, 3], [3, 4], [5, 6]])
  296. )
  297. def test_assert_almost_equal_value_mismatch4():
  298. msg = """numpy array are different
  299. numpy array values are different \\(25\\.0 %\\)
  300. \\[left\\]: \\[\\[1, 2\\], \\[3, 4\\]\\]
  301. \\[right\\]: \\[\\[1, 3\\], \\[3, 4\\]\\]"""
  302. with pytest.raises(AssertionError, match=msg):
  303. tm.assert_almost_equal(np.array([[1, 2], [3, 4]]), np.array([[1, 3], [3, 4]]))
  304. def test_assert_almost_equal_shape_mismatch_override():
  305. msg = """Index are different
  306. Index shapes are different
  307. \\[left\\]: \\(2L*,\\)
  308. \\[right\\]: \\(3L*,\\)"""
  309. with pytest.raises(AssertionError, match=msg):
  310. tm.assert_almost_equal(np.array([1, 2]), np.array([3, 4, 5]), obj="Index")
  311. def test_assert_almost_equal_unicode():
  312. # see gh-20503
  313. msg = """numpy array are different
  314. numpy array values are different \\(33\\.33333 %\\)
  315. \\[left\\]: \\[á, à, ä\\]
  316. \\[right\\]: \\[á, à, å\\]"""
  317. with pytest.raises(AssertionError, match=msg):
  318. tm.assert_almost_equal(np.array(["á", "à", "ä"]), np.array(["á", "à", "å"]))
  319. def test_assert_almost_equal_timestamp():
  320. a = np.array([Timestamp("2011-01-01"), Timestamp("2011-01-01")])
  321. b = np.array([Timestamp("2011-01-01"), Timestamp("2011-01-02")])
  322. msg = """numpy array are different
  323. numpy array values are different \\(50\\.0 %\\)
  324. \\[left\\]: \\[2011-01-01 00:00:00, 2011-01-01 00:00:00\\]
  325. \\[right\\]: \\[2011-01-01 00:00:00, 2011-01-02 00:00:00\\]"""
  326. with pytest.raises(AssertionError, match=msg):
  327. tm.assert_almost_equal(a, b)
  328. def test_assert_almost_equal_iterable_length_mismatch():
  329. msg = """Iterable are different
  330. Iterable length are different
  331. \\[left\\]: 2
  332. \\[right\\]: 3"""
  333. with pytest.raises(AssertionError, match=msg):
  334. tm.assert_almost_equal([1, 2], [3, 4, 5])
  335. def test_assert_almost_equal_iterable_values_mismatch():
  336. msg = """Iterable are different
  337. Iterable values are different \\(50\\.0 %\\)
  338. \\[left\\]: \\[1, 2\\]
  339. \\[right\\]: \\[1, 3\\]"""
  340. with pytest.raises(AssertionError, match=msg):
  341. tm.assert_almost_equal([1, 2], [1, 3])
  342. subarr = np.empty(2, dtype=object)
  343. subarr[:] = [np.array([None, "b"], dtype=object), np.array(["c", "d"], dtype=object)]
  344. NESTED_CASES = [
  345. # nested array
  346. (
  347. np.array([np.array([50, 70, 90]), np.array([20, 30])], dtype=object),
  348. np.array([np.array([50, 70, 90]), np.array([20, 30])], dtype=object),
  349. ),
  350. # >1 level of nesting
  351. (
  352. np.array(
  353. [
  354. np.array([np.array([50, 70]), np.array([90])], dtype=object),
  355. np.array([np.array([20, 30])], dtype=object),
  356. ],
  357. dtype=object,
  358. ),
  359. np.array(
  360. [
  361. np.array([np.array([50, 70]), np.array([90])], dtype=object),
  362. np.array([np.array([20, 30])], dtype=object),
  363. ],
  364. dtype=object,
  365. ),
  366. ),
  367. # lists
  368. (
  369. np.array([[50, 70, 90], [20, 30]], dtype=object),
  370. np.array([[50, 70, 90], [20, 30]], dtype=object),
  371. ),
  372. # mixed array/list
  373. (
  374. np.array([np.array([1, 2, 3]), np.array([4, 5])], dtype=object),
  375. np.array([[1, 2, 3], [4, 5]], dtype=object),
  376. ),
  377. (
  378. np.array(
  379. [
  380. np.array([np.array([1, 2, 3]), np.array([4, 5])], dtype=object),
  381. np.array(
  382. [np.array([6]), np.array([7, 8]), np.array([9])], dtype=object
  383. ),
  384. ],
  385. dtype=object,
  386. ),
  387. np.array([[[1, 2, 3], [4, 5]], [[6], [7, 8], [9]]], dtype=object),
  388. ),
  389. # same-length lists
  390. (
  391. np.array([subarr, None], dtype=object),
  392. np.array([list([[None, "b"], ["c", "d"]]), None], dtype=object),
  393. ),
  394. # dicts
  395. (
  396. np.array([{"f1": 1, "f2": np.array(["a", "b"], dtype=object)}], dtype=object),
  397. np.array([{"f1": 1, "f2": np.array(["a", "b"], dtype=object)}], dtype=object),
  398. ),
  399. (
  400. np.array([{"f1": 1, "f2": np.array(["a", "b"], dtype=object)}], dtype=object),
  401. np.array([{"f1": 1, "f2": ["a", "b"]}], dtype=object),
  402. ),
  403. # array/list of dicts
  404. (
  405. np.array(
  406. [
  407. np.array(
  408. [{"f1": 1, "f2": np.array(["a", "b"], dtype=object)}], dtype=object
  409. ),
  410. np.array([], dtype=object),
  411. ],
  412. dtype=object,
  413. ),
  414. np.array([[{"f1": 1, "f2": ["a", "b"]}], []], dtype=object),
  415. ),
  416. ]
  417. @pytest.mark.filterwarnings("ignore:elementwise comparison failed:DeprecationWarning")
  418. @pytest.mark.parametrize("a,b", NESTED_CASES)
  419. def test_assert_almost_equal_array_nested(a, b):
  420. _assert_almost_equal_both(a, b)