test_numpy.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. """
  2. Additional tests for PandasArray that aren't covered by
  3. the interface tests.
  4. """
  5. import numpy as np
  6. import pytest
  7. from pandas.core.dtypes.dtypes import PandasDtype
  8. import pandas as pd
  9. import pandas._testing as tm
  10. from pandas.arrays import PandasArray
  11. @pytest.fixture(
  12. params=[
  13. np.array(["a", "b"], dtype=object),
  14. np.array([0, 1], dtype=float),
  15. np.array([0, 1], dtype=int),
  16. np.array([0, 1 + 2j], dtype=complex),
  17. np.array([True, False], dtype=bool),
  18. np.array([0, 1], dtype="datetime64[ns]"),
  19. np.array([0, 1], dtype="timedelta64[ns]"),
  20. ]
  21. )
  22. def any_numpy_array(request):
  23. """
  24. Parametrized fixture for NumPy arrays with different dtypes.
  25. This excludes string and bytes.
  26. """
  27. return request.param
  28. # ----------------------------------------------------------------------------
  29. # PandasDtype
  30. @pytest.mark.parametrize(
  31. "dtype, expected",
  32. [
  33. ("bool", True),
  34. ("int", True),
  35. ("uint", True),
  36. ("float", True),
  37. ("complex", True),
  38. ("str", False),
  39. ("bytes", False),
  40. ("datetime64[ns]", False),
  41. ("object", False),
  42. ("void", False),
  43. ],
  44. )
  45. def test_is_numeric(dtype, expected):
  46. dtype = PandasDtype(dtype)
  47. assert dtype._is_numeric is expected
  48. @pytest.mark.parametrize(
  49. "dtype, expected",
  50. [
  51. ("bool", True),
  52. ("int", False),
  53. ("uint", False),
  54. ("float", False),
  55. ("complex", False),
  56. ("str", False),
  57. ("bytes", False),
  58. ("datetime64[ns]", False),
  59. ("object", False),
  60. ("void", False),
  61. ],
  62. )
  63. def test_is_boolean(dtype, expected):
  64. dtype = PandasDtype(dtype)
  65. assert dtype._is_boolean is expected
  66. def test_repr():
  67. dtype = PandasDtype(np.dtype("int64"))
  68. assert repr(dtype) == "PandasDtype('int64')"
  69. def test_constructor_from_string():
  70. result = PandasDtype.construct_from_string("int64")
  71. expected = PandasDtype(np.dtype("int64"))
  72. assert result == expected
  73. def test_dtype_univalent(any_numpy_dtype):
  74. dtype = PandasDtype(any_numpy_dtype)
  75. result = PandasDtype(dtype)
  76. assert result == dtype
  77. # ----------------------------------------------------------------------------
  78. # Construction
  79. def test_constructor_no_coercion():
  80. with pytest.raises(ValueError, match="NumPy array"):
  81. PandasArray([1, 2, 3])
  82. def test_series_constructor_with_copy():
  83. ndarray = np.array([1, 2, 3])
  84. ser = pd.Series(PandasArray(ndarray), copy=True)
  85. assert ser.values is not ndarray
  86. def test_series_constructor_with_astype():
  87. ndarray = np.array([1, 2, 3])
  88. result = pd.Series(PandasArray(ndarray), dtype="float64")
  89. expected = pd.Series([1.0, 2.0, 3.0], dtype="float64")
  90. tm.assert_series_equal(result, expected)
  91. def test_from_sequence_dtype():
  92. arr = np.array([1, 2, 3], dtype="int64")
  93. result = PandasArray._from_sequence(arr, dtype="uint64")
  94. expected = PandasArray(np.array([1, 2, 3], dtype="uint64"))
  95. tm.assert_extension_array_equal(result, expected)
  96. def test_constructor_copy():
  97. arr = np.array([0, 1])
  98. result = PandasArray(arr, copy=True)
  99. assert not tm.shares_memory(result, arr)
  100. def test_constructor_with_data(any_numpy_array):
  101. nparr = any_numpy_array
  102. arr = PandasArray(nparr)
  103. assert arr.dtype.numpy_dtype == nparr.dtype
  104. # ----------------------------------------------------------------------------
  105. # Conversion
  106. def test_to_numpy():
  107. arr = PandasArray(np.array([1, 2, 3]))
  108. result = arr.to_numpy()
  109. assert result is arr._ndarray
  110. result = arr.to_numpy(copy=True)
  111. assert result is not arr._ndarray
  112. result = arr.to_numpy(dtype="f8")
  113. expected = np.array([1, 2, 3], dtype="f8")
  114. tm.assert_numpy_array_equal(result, expected)
  115. # ----------------------------------------------------------------------------
  116. # Setitem
  117. def test_setitem_series():
  118. ser = pd.Series([1, 2, 3])
  119. ser.array[0] = 10
  120. expected = pd.Series([10, 2, 3])
  121. tm.assert_series_equal(ser, expected)
  122. def test_setitem(any_numpy_array):
  123. nparr = any_numpy_array
  124. arr = PandasArray(nparr, copy=True)
  125. arr[0] = arr[1]
  126. nparr[0] = nparr[1]
  127. tm.assert_numpy_array_equal(arr.to_numpy(), nparr)
  128. # ----------------------------------------------------------------------------
  129. # Reductions
  130. def test_bad_reduce_raises():
  131. arr = np.array([1, 2, 3], dtype="int64")
  132. arr = PandasArray(arr)
  133. msg = "cannot perform not_a_method with type int"
  134. with pytest.raises(TypeError, match=msg):
  135. arr._reduce(msg)
  136. def test_validate_reduction_keyword_args():
  137. arr = PandasArray(np.array([1, 2, 3]))
  138. msg = "the 'keepdims' parameter is not supported .*all"
  139. with pytest.raises(ValueError, match=msg):
  140. arr.all(keepdims=True)
  141. def test_np_max_nested_tuples():
  142. # case where checking in ufunc.nout works while checking for tuples
  143. # does not
  144. vals = [
  145. (("j", "k"), ("l", "m")),
  146. (("l", "m"), ("o", "p")),
  147. (("o", "p"), ("j", "k")),
  148. ]
  149. ser = pd.Series(vals)
  150. arr = ser.array
  151. assert arr.max() is arr[2]
  152. assert ser.max() is arr[2]
  153. result = np.maximum.reduce(arr)
  154. assert result == arr[2]
  155. result = np.maximum.reduce(ser)
  156. assert result == arr[2]
  157. def test_np_reduce_2d():
  158. raw = np.arange(12).reshape(4, 3)
  159. arr = PandasArray(raw)
  160. res = np.maximum.reduce(arr, axis=0)
  161. tm.assert_extension_array_equal(res, arr[-1])
  162. alt = arr.max(axis=0)
  163. tm.assert_extension_array_equal(alt, arr[-1])
  164. # ----------------------------------------------------------------------------
  165. # Ops
  166. @pytest.mark.parametrize("ufunc", [np.abs, np.negative, np.positive])
  167. def test_ufunc_unary(ufunc):
  168. arr = PandasArray(np.array([-1.0, 0.0, 1.0]))
  169. result = ufunc(arr)
  170. expected = PandasArray(ufunc(arr._ndarray))
  171. tm.assert_extension_array_equal(result, expected)
  172. # same thing but with the 'out' keyword
  173. out = PandasArray(np.array([-9.0, -9.0, -9.0]))
  174. ufunc(arr, out=out)
  175. tm.assert_extension_array_equal(out, expected)
  176. def test_ufunc():
  177. arr = PandasArray(np.array([-1.0, 0.0, 1.0]))
  178. r1, r2 = np.divmod(arr, np.add(arr, 2))
  179. e1, e2 = np.divmod(arr._ndarray, np.add(arr._ndarray, 2))
  180. e1 = PandasArray(e1)
  181. e2 = PandasArray(e2)
  182. tm.assert_extension_array_equal(r1, e1)
  183. tm.assert_extension_array_equal(r2, e2)
  184. def test_basic_binop():
  185. # Just a basic smoke test. The EA interface tests exercise this
  186. # more thoroughly.
  187. x = PandasArray(np.array([1, 2, 3]))
  188. result = x + x
  189. expected = PandasArray(np.array([2, 4, 6]))
  190. tm.assert_extension_array_equal(result, expected)
  191. @pytest.mark.parametrize("dtype", [None, object])
  192. def test_setitem_object_typecode(dtype):
  193. arr = PandasArray(np.array(["a", "b", "c"], dtype=dtype))
  194. arr[0] = "t"
  195. expected = PandasArray(np.array(["t", "b", "c"], dtype=dtype))
  196. tm.assert_extension_array_equal(arr, expected)
  197. def test_setitem_no_coercion():
  198. # https://github.com/pandas-dev/pandas/issues/28150
  199. arr = PandasArray(np.array([1, 2, 3]))
  200. with pytest.raises(ValueError, match="int"):
  201. arr[0] = "a"
  202. # With a value that we do coerce, check that we coerce the value
  203. # and not the underlying array.
  204. arr[0] = 2.5
  205. assert isinstance(arr[0], (int, np.integer)), type(arr[0])
  206. def test_setitem_preserves_views():
  207. # GH#28150, see also extension test of the same name
  208. arr = PandasArray(np.array([1, 2, 3]))
  209. view1 = arr.view()
  210. view2 = arr[:]
  211. view3 = np.asarray(arr)
  212. arr[0] = 9
  213. assert view1[0] == 9
  214. assert view2[0] == 9
  215. assert view3[0] == 9
  216. arr[-1] = 2.5
  217. view1[-1] = 5
  218. assert arr[-1] == 5
  219. @pytest.mark.parametrize("dtype", [np.int64, np.uint64])
  220. def test_quantile_empty(dtype):
  221. # we should get back np.nans, not -1s
  222. arr = PandasArray(np.array([], dtype=dtype))
  223. idx = pd.Index([0.0, 0.5])
  224. result = arr._quantile(idx, interpolation="linear")
  225. expected = PandasArray(np.array([np.nan, np.nan]))
  226. tm.assert_extension_array_equal(result, expected)
  227. def test_factorize_unsigned():
  228. # don't raise when calling factorize on unsigned int PandasArray
  229. arr = np.array([1, 2, 3], dtype=np.uint64)
  230. obj = PandasArray(arr)
  231. res_codes, res_unique = obj.factorize()
  232. exp_codes, exp_unique = pd.factorize(arr)
  233. tm.assert_numpy_array_equal(res_codes, exp_codes)
  234. tm.assert_extension_array_equal(res_unique, PandasArray(exp_unique))