PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/pandas/_libs/testing.pyx

https://github.com/neurodebian/pandas
Cython | 213 lines | 176 code | 29 blank | 8 comment | 36 complexity | 7ec72fa9e36daf39e5c49844da411e7b MD5 | raw file
  1. import numpy as np
  2. from pandas import compat
  3. from pandas.core.dtypes.missing import isna, array_equivalent
  4. from pandas.core.dtypes.common import is_dtype_equal
  5. cdef NUMERIC_TYPES = (
  6. bool,
  7. int,
  8. float,
  9. np.bool,
  10. np.int8,
  11. np.int16,
  12. np.int32,
  13. np.int64,
  14. np.uint8,
  15. np.uint16,
  16. np.uint32,
  17. np.uint64,
  18. np.float16,
  19. np.float32,
  20. np.float64,
  21. )
  22. cdef bint is_comparable_as_number(obj):
  23. return isinstance(obj, NUMERIC_TYPES)
  24. cdef bint isiterable(obj):
  25. return hasattr(obj, '__iter__')
  26. cdef bint has_length(obj):
  27. return hasattr(obj, '__len__')
  28. cdef bint is_dictlike(obj):
  29. return hasattr(obj, 'keys') and hasattr(obj, '__getitem__')
  30. cdef bint decimal_almost_equal(double desired, double actual, int decimal):
  31. # Code from
  32. # http://docs.scipy.org/doc/numpy/reference/generated
  33. # /numpy.testing.assert_almost_equal.html
  34. return abs(desired - actual) < (0.5 * 10.0 ** -decimal)
  35. cpdef assert_dict_equal(a, b, bint compare_keys=True):
  36. assert is_dictlike(a) and is_dictlike(b), (
  37. "Cannot compare dict objects, one or both is not dict-like"
  38. )
  39. a_keys = frozenset(a.keys())
  40. b_keys = frozenset(b.keys())
  41. if compare_keys:
  42. assert a_keys == b_keys
  43. for k in a_keys:
  44. assert_almost_equal(a[k], b[k])
  45. return True
  46. cpdef assert_almost_equal(a, b,
  47. check_less_precise=False,
  48. bint check_dtype=True,
  49. obj=None, lobj=None, robj=None):
  50. """Check that left and right objects are almost equal.
  51. Parameters
  52. ----------
  53. a : object
  54. b : object
  55. check_less_precise : bool or int, default False
  56. Specify comparison precision.
  57. 5 digits (False) or 3 digits (True) after decimal points are
  58. compared. If an integer, then this will be the number of decimal
  59. points to compare
  60. check_dtype: bool, default True
  61. check dtype if both a and b are np.ndarray
  62. obj : str, default None
  63. Specify object name being compared, internally used to show
  64. appropriate assertion message
  65. lobj : str, default None
  66. Specify left object name being compared, internally used to show
  67. appropriate assertion message
  68. robj : str, default None
  69. Specify right object name being compared, internally used to show
  70. appropriate assertion message
  71. """
  72. cdef:
  73. int decimal
  74. double diff = 0.0
  75. Py_ssize_t i, na, nb
  76. double fa, fb
  77. bint is_unequal = False, a_is_ndarray, b_is_ndarray
  78. if lobj is None:
  79. lobj = a
  80. if robj is None:
  81. robj = b
  82. assert isinstance(check_less_precise, (int, bool))
  83. if isinstance(a, dict) or isinstance(b, dict):
  84. return assert_dict_equal(a, b)
  85. if (isinstance(a, compat.string_types) or
  86. isinstance(b, compat.string_types)):
  87. assert a == b, "%r != %r" % (a, b)
  88. return True
  89. a_is_ndarray = isinstance(a, np.ndarray)
  90. b_is_ndarray = isinstance(b, np.ndarray)
  91. if obj is None:
  92. if a_is_ndarray or b_is_ndarray:
  93. obj = 'numpy array'
  94. else:
  95. obj = 'Iterable'
  96. if isiterable(a):
  97. if not isiterable(b):
  98. from pandas.util.testing import assert_class_equal
  99. # classes can't be the same, to raise error
  100. assert_class_equal(a, b, obj=obj)
  101. assert has_length(a) and has_length(b), (
  102. "Can't compare objects without length, one or both is invalid: "
  103. "(%r, %r)" % (a, b))
  104. if a_is_ndarray and b_is_ndarray:
  105. na, nb = a.size, b.size
  106. if a.shape != b.shape:
  107. from pandas.util.testing import raise_assert_detail
  108. raise_assert_detail(
  109. obj, '{0} shapes are different'.format(obj),
  110. a.shape, b.shape)
  111. if check_dtype and not is_dtype_equal(a, b):
  112. from pandas.util.testing import assert_attr_equal
  113. assert_attr_equal('dtype', a, b, obj=obj)
  114. try:
  115. if array_equivalent(a, b, strict_nan=True):
  116. return True
  117. except:
  118. pass
  119. else:
  120. na, nb = len(a), len(b)
  121. if na != nb:
  122. from pandas.util.testing import raise_assert_detail
  123. # if we have a small diff set, print it
  124. if abs(na - nb) < 10:
  125. r = list(set(a) ^ set(b))
  126. else:
  127. r = None
  128. raise_assert_detail(obj, '{0} length are different'.format(obj),
  129. na, nb, r)
  130. for i in xrange(len(a)):
  131. try:
  132. assert_almost_equal(a[i], b[i],
  133. check_less_precise=check_less_precise)
  134. except AssertionError:
  135. is_unequal = True
  136. diff += 1
  137. if is_unequal:
  138. from pandas.util.testing import raise_assert_detail
  139. msg = '{0} values are different ({1} %)'.format(
  140. obj, np.round(diff * 100.0 / na, 5))
  141. raise_assert_detail(obj, msg, lobj, robj)
  142. return True
  143. elif isiterable(b):
  144. from pandas.util.testing import assert_class_equal
  145. # classes can't be the same, to raise error
  146. assert_class_equal(a, b, obj=obj)
  147. if a == b:
  148. # object comparison
  149. return True
  150. if isna(a) and isna(b):
  151. # nan / None comparison
  152. return True
  153. if is_comparable_as_number(a) and is_comparable_as_number(b):
  154. if array_equivalent(a, b, strict_nan=True):
  155. # inf comparison
  156. return True
  157. if check_less_precise is True:
  158. decimal = 3
  159. elif check_less_precise is False:
  160. decimal = 5
  161. else:
  162. decimal = check_less_precise
  163. fa, fb = a, b
  164. # case for zero
  165. if abs(fa) < 1e-5:
  166. if not decimal_almost_equal(fa, fb, decimal):
  167. assert False, ('(very low values) expected %.5f but '
  168. 'got %.5f, with decimal %d' % (fb, fa, decimal))
  169. else:
  170. if not decimal_almost_equal(1, fb / fa, decimal):
  171. assert False, ('expected %.5f but got %.5f, '
  172. 'with decimal %d' % (fb, fa, decimal))
  173. return True
  174. raise AssertionError("{0} != {1}".format(a, b))