test_arithmetics.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. import operator
  2. import numpy as np
  3. import pytest
  4. import pandas as pd
  5. from pandas import SparseDtype
  6. import pandas._testing as tm
  7. from pandas.core.arrays.sparse import SparseArray
  8. @pytest.fixture(params=["integer", "block"])
  9. def kind(request):
  10. """kind kwarg to pass to SparseArray"""
  11. return request.param
  12. @pytest.fixture(params=[True, False])
  13. def mix(request):
  14. """
  15. Fixture returning True or False, determining whether to operate
  16. op(sparse, dense) instead of op(sparse, sparse)
  17. """
  18. return request.param
  19. class TestSparseArrayArithmetics:
  20. def _assert(self, a, b):
  21. # We have to use tm.assert_sp_array_equal. See GH #45126
  22. tm.assert_numpy_array_equal(a, b)
  23. def _check_numeric_ops(self, a, b, a_dense, b_dense, mix: bool, op):
  24. # Check that arithmetic behavior matches non-Sparse Series arithmetic
  25. if isinstance(a_dense, np.ndarray):
  26. expected = op(pd.Series(a_dense), b_dense).values
  27. elif isinstance(b_dense, np.ndarray):
  28. expected = op(a_dense, pd.Series(b_dense)).values
  29. else:
  30. raise NotImplementedError
  31. with np.errstate(invalid="ignore", divide="ignore"):
  32. if mix:
  33. result = op(a, b_dense).to_dense()
  34. else:
  35. result = op(a, b).to_dense()
  36. self._assert(result, expected)
  37. def _check_bool_result(self, res):
  38. assert isinstance(res, SparseArray)
  39. assert isinstance(res.dtype, SparseDtype)
  40. assert res.dtype.subtype == np.bool_
  41. assert isinstance(res.fill_value, bool)
  42. def _check_comparison_ops(self, a, b, a_dense, b_dense):
  43. with np.errstate(invalid="ignore"):
  44. # Unfortunately, trying to wrap the computation of each expected
  45. # value is with np.errstate() is too tedious.
  46. #
  47. # sparse & sparse
  48. self._check_bool_result(a == b)
  49. self._assert((a == b).to_dense(), a_dense == b_dense)
  50. self._check_bool_result(a != b)
  51. self._assert((a != b).to_dense(), a_dense != b_dense)
  52. self._check_bool_result(a >= b)
  53. self._assert((a >= b).to_dense(), a_dense >= b_dense)
  54. self._check_bool_result(a <= b)
  55. self._assert((a <= b).to_dense(), a_dense <= b_dense)
  56. self._check_bool_result(a > b)
  57. self._assert((a > b).to_dense(), a_dense > b_dense)
  58. self._check_bool_result(a < b)
  59. self._assert((a < b).to_dense(), a_dense < b_dense)
  60. # sparse & dense
  61. self._check_bool_result(a == b_dense)
  62. self._assert((a == b_dense).to_dense(), a_dense == b_dense)
  63. self._check_bool_result(a != b_dense)
  64. self._assert((a != b_dense).to_dense(), a_dense != b_dense)
  65. self._check_bool_result(a >= b_dense)
  66. self._assert((a >= b_dense).to_dense(), a_dense >= b_dense)
  67. self._check_bool_result(a <= b_dense)
  68. self._assert((a <= b_dense).to_dense(), a_dense <= b_dense)
  69. self._check_bool_result(a > b_dense)
  70. self._assert((a > b_dense).to_dense(), a_dense > b_dense)
  71. self._check_bool_result(a < b_dense)
  72. self._assert((a < b_dense).to_dense(), a_dense < b_dense)
  73. def _check_logical_ops(self, a, b, a_dense, b_dense):
  74. # sparse & sparse
  75. self._check_bool_result(a & b)
  76. self._assert((a & b).to_dense(), a_dense & b_dense)
  77. self._check_bool_result(a | b)
  78. self._assert((a | b).to_dense(), a_dense | b_dense)
  79. # sparse & dense
  80. self._check_bool_result(a & b_dense)
  81. self._assert((a & b_dense).to_dense(), a_dense & b_dense)
  82. self._check_bool_result(a | b_dense)
  83. self._assert((a | b_dense).to_dense(), a_dense | b_dense)
  84. @pytest.mark.parametrize("scalar", [0, 1, 3])
  85. @pytest.mark.parametrize("fill_value", [None, 0, 2])
  86. def test_float_scalar(
  87. self, kind, mix, all_arithmetic_functions, fill_value, scalar, request
  88. ):
  89. op = all_arithmetic_functions
  90. values = np.array([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan])
  91. a = SparseArray(values, kind=kind, fill_value=fill_value)
  92. self._check_numeric_ops(a, scalar, values, scalar, mix, op)
  93. def test_float_scalar_comparison(self, kind):
  94. values = np.array([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan])
  95. a = SparseArray(values, kind=kind)
  96. self._check_comparison_ops(a, 1, values, 1)
  97. self._check_comparison_ops(a, 0, values, 0)
  98. self._check_comparison_ops(a, 3, values, 3)
  99. a = SparseArray(values, kind=kind, fill_value=0)
  100. self._check_comparison_ops(a, 1, values, 1)
  101. self._check_comparison_ops(a, 0, values, 0)
  102. self._check_comparison_ops(a, 3, values, 3)
  103. a = SparseArray(values, kind=kind, fill_value=2)
  104. self._check_comparison_ops(a, 1, values, 1)
  105. self._check_comparison_ops(a, 0, values, 0)
  106. self._check_comparison_ops(a, 3, values, 3)
  107. def test_float_same_index_without_nans(self, kind, mix, all_arithmetic_functions):
  108. # when sp_index are the same
  109. op = all_arithmetic_functions
  110. values = np.array([0.0, 1.0, 2.0, 6.0, 0.0, 0.0, 1.0, 2.0, 1.0, 0.0])
  111. rvalues = np.array([0.0, 2.0, 3.0, 4.0, 0.0, 0.0, 1.0, 3.0, 2.0, 0.0])
  112. a = SparseArray(values, kind=kind, fill_value=0)
  113. b = SparseArray(rvalues, kind=kind, fill_value=0)
  114. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  115. def test_float_same_index_with_nans(
  116. self, kind, mix, all_arithmetic_functions, request
  117. ):
  118. # when sp_index are the same
  119. op = all_arithmetic_functions
  120. values = np.array([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan])
  121. rvalues = np.array([np.nan, 2, 3, 4, np.nan, 0, 1, 3, 2, np.nan])
  122. a = SparseArray(values, kind=kind)
  123. b = SparseArray(rvalues, kind=kind)
  124. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  125. def test_float_same_index_comparison(self, kind):
  126. # when sp_index are the same
  127. values = np.array([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan])
  128. rvalues = np.array([np.nan, 2, 3, 4, np.nan, 0, 1, 3, 2, np.nan])
  129. a = SparseArray(values, kind=kind)
  130. b = SparseArray(rvalues, kind=kind)
  131. self._check_comparison_ops(a, b, values, rvalues)
  132. values = np.array([0.0, 1.0, 2.0, 6.0, 0.0, 0.0, 1.0, 2.0, 1.0, 0.0])
  133. rvalues = np.array([0.0, 2.0, 3.0, 4.0, 0.0, 0.0, 1.0, 3.0, 2.0, 0.0])
  134. a = SparseArray(values, kind=kind, fill_value=0)
  135. b = SparseArray(rvalues, kind=kind, fill_value=0)
  136. self._check_comparison_ops(a, b, values, rvalues)
  137. def test_float_array(self, kind, mix, all_arithmetic_functions):
  138. op = all_arithmetic_functions
  139. values = np.array([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan])
  140. rvalues = np.array([2, np.nan, 2, 3, np.nan, 0, 1, 5, 2, np.nan])
  141. a = SparseArray(values, kind=kind)
  142. b = SparseArray(rvalues, kind=kind)
  143. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  144. self._check_numeric_ops(a, b * 0, values, rvalues * 0, mix, op)
  145. a = SparseArray(values, kind=kind, fill_value=0)
  146. b = SparseArray(rvalues, kind=kind)
  147. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  148. a = SparseArray(values, kind=kind, fill_value=0)
  149. b = SparseArray(rvalues, kind=kind, fill_value=0)
  150. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  151. a = SparseArray(values, kind=kind, fill_value=1)
  152. b = SparseArray(rvalues, kind=kind, fill_value=2)
  153. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  154. def test_float_array_different_kind(self, mix, all_arithmetic_functions):
  155. op = all_arithmetic_functions
  156. values = np.array([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan])
  157. rvalues = np.array([2, np.nan, 2, 3, np.nan, 0, 1, 5, 2, np.nan])
  158. a = SparseArray(values, kind="integer")
  159. b = SparseArray(rvalues, kind="block")
  160. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  161. self._check_numeric_ops(a, b * 0, values, rvalues * 0, mix, op)
  162. a = SparseArray(values, kind="integer", fill_value=0)
  163. b = SparseArray(rvalues, kind="block")
  164. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  165. a = SparseArray(values, kind="integer", fill_value=0)
  166. b = SparseArray(rvalues, kind="block", fill_value=0)
  167. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  168. a = SparseArray(values, kind="integer", fill_value=1)
  169. b = SparseArray(rvalues, kind="block", fill_value=2)
  170. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  171. def test_float_array_comparison(self, kind):
  172. values = np.array([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan])
  173. rvalues = np.array([2, np.nan, 2, 3, np.nan, 0, 1, 5, 2, np.nan])
  174. a = SparseArray(values, kind=kind)
  175. b = SparseArray(rvalues, kind=kind)
  176. self._check_comparison_ops(a, b, values, rvalues)
  177. self._check_comparison_ops(a, b * 0, values, rvalues * 0)
  178. a = SparseArray(values, kind=kind, fill_value=0)
  179. b = SparseArray(rvalues, kind=kind)
  180. self._check_comparison_ops(a, b, values, rvalues)
  181. a = SparseArray(values, kind=kind, fill_value=0)
  182. b = SparseArray(rvalues, kind=kind, fill_value=0)
  183. self._check_comparison_ops(a, b, values, rvalues)
  184. a = SparseArray(values, kind=kind, fill_value=1)
  185. b = SparseArray(rvalues, kind=kind, fill_value=2)
  186. self._check_comparison_ops(a, b, values, rvalues)
  187. def test_int_array(self, kind, mix, all_arithmetic_functions):
  188. op = all_arithmetic_functions
  189. # have to specify dtype explicitly until fixing GH 667
  190. dtype = np.int64
  191. values = np.array([0, 1, 2, 0, 0, 0, 1, 2, 1, 0], dtype=dtype)
  192. rvalues = np.array([2, 0, 2, 3, 0, 0, 1, 5, 2, 0], dtype=dtype)
  193. a = SparseArray(values, dtype=dtype, kind=kind)
  194. assert a.dtype == SparseDtype(dtype)
  195. b = SparseArray(rvalues, dtype=dtype, kind=kind)
  196. assert b.dtype == SparseDtype(dtype)
  197. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  198. self._check_numeric_ops(a, b * 0, values, rvalues * 0, mix, op)
  199. a = SparseArray(values, fill_value=0, dtype=dtype, kind=kind)
  200. assert a.dtype == SparseDtype(dtype)
  201. b = SparseArray(rvalues, dtype=dtype, kind=kind)
  202. assert b.dtype == SparseDtype(dtype)
  203. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  204. a = SparseArray(values, fill_value=0, dtype=dtype, kind=kind)
  205. assert a.dtype == SparseDtype(dtype)
  206. b = SparseArray(rvalues, fill_value=0, dtype=dtype, kind=kind)
  207. assert b.dtype == SparseDtype(dtype)
  208. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  209. a = SparseArray(values, fill_value=1, dtype=dtype, kind=kind)
  210. assert a.dtype == SparseDtype(dtype, fill_value=1)
  211. b = SparseArray(rvalues, fill_value=2, dtype=dtype, kind=kind)
  212. assert b.dtype == SparseDtype(dtype, fill_value=2)
  213. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  214. def test_int_array_comparison(self, kind):
  215. dtype = "int64"
  216. # int32 NI ATM
  217. values = np.array([0, 1, 2, 0, 0, 0, 1, 2, 1, 0], dtype=dtype)
  218. rvalues = np.array([2, 0, 2, 3, 0, 0, 1, 5, 2, 0], dtype=dtype)
  219. a = SparseArray(values, dtype=dtype, kind=kind)
  220. b = SparseArray(rvalues, dtype=dtype, kind=kind)
  221. self._check_comparison_ops(a, b, values, rvalues)
  222. self._check_comparison_ops(a, b * 0, values, rvalues * 0)
  223. a = SparseArray(values, dtype=dtype, kind=kind, fill_value=0)
  224. b = SparseArray(rvalues, dtype=dtype, kind=kind)
  225. self._check_comparison_ops(a, b, values, rvalues)
  226. a = SparseArray(values, dtype=dtype, kind=kind, fill_value=0)
  227. b = SparseArray(rvalues, dtype=dtype, kind=kind, fill_value=0)
  228. self._check_comparison_ops(a, b, values, rvalues)
  229. a = SparseArray(values, dtype=dtype, kind=kind, fill_value=1)
  230. b = SparseArray(rvalues, dtype=dtype, kind=kind, fill_value=2)
  231. self._check_comparison_ops(a, b, values, rvalues)
  232. @pytest.mark.parametrize("fill_value", [True, False, np.nan])
  233. def test_bool_same_index(self, kind, fill_value):
  234. # GH 14000
  235. # when sp_index are the same
  236. values = np.array([True, False, True, True], dtype=np.bool_)
  237. rvalues = np.array([True, False, True, True], dtype=np.bool_)
  238. a = SparseArray(values, kind=kind, dtype=np.bool_, fill_value=fill_value)
  239. b = SparseArray(rvalues, kind=kind, dtype=np.bool_, fill_value=fill_value)
  240. self._check_logical_ops(a, b, values, rvalues)
  241. @pytest.mark.parametrize("fill_value", [True, False, np.nan])
  242. def test_bool_array_logical(self, kind, fill_value):
  243. # GH 14000
  244. # when sp_index are the same
  245. values = np.array([True, False, True, False, True, True], dtype=np.bool_)
  246. rvalues = np.array([True, False, False, True, False, True], dtype=np.bool_)
  247. a = SparseArray(values, kind=kind, dtype=np.bool_, fill_value=fill_value)
  248. b = SparseArray(rvalues, kind=kind, dtype=np.bool_, fill_value=fill_value)
  249. self._check_logical_ops(a, b, values, rvalues)
  250. def test_mixed_array_float_int(self, kind, mix, all_arithmetic_functions, request):
  251. op = all_arithmetic_functions
  252. rdtype = "int64"
  253. values = np.array([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan])
  254. rvalues = np.array([2, 0, 2, 3, 0, 0, 1, 5, 2, 0], dtype=rdtype)
  255. a = SparseArray(values, kind=kind)
  256. b = SparseArray(rvalues, kind=kind)
  257. assert b.dtype == SparseDtype(rdtype)
  258. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  259. self._check_numeric_ops(a, b * 0, values, rvalues * 0, mix, op)
  260. a = SparseArray(values, kind=kind, fill_value=0)
  261. b = SparseArray(rvalues, kind=kind)
  262. assert b.dtype == SparseDtype(rdtype)
  263. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  264. a = SparseArray(values, kind=kind, fill_value=0)
  265. b = SparseArray(rvalues, kind=kind, fill_value=0)
  266. assert b.dtype == SparseDtype(rdtype)
  267. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  268. a = SparseArray(values, kind=kind, fill_value=1)
  269. b = SparseArray(rvalues, kind=kind, fill_value=2)
  270. assert b.dtype == SparseDtype(rdtype, fill_value=2)
  271. self._check_numeric_ops(a, b, values, rvalues, mix, op)
  272. def test_mixed_array_comparison(self, kind):
  273. rdtype = "int64"
  274. # int32 NI ATM
  275. values = np.array([np.nan, 1, 2, 0, np.nan, 0, 1, 2, 1, np.nan])
  276. rvalues = np.array([2, 0, 2, 3, 0, 0, 1, 5, 2, 0], dtype=rdtype)
  277. a = SparseArray(values, kind=kind)
  278. b = SparseArray(rvalues, kind=kind)
  279. assert b.dtype == SparseDtype(rdtype)
  280. self._check_comparison_ops(a, b, values, rvalues)
  281. self._check_comparison_ops(a, b * 0, values, rvalues * 0)
  282. a = SparseArray(values, kind=kind, fill_value=0)
  283. b = SparseArray(rvalues, kind=kind)
  284. assert b.dtype == SparseDtype(rdtype)
  285. self._check_comparison_ops(a, b, values, rvalues)
  286. a = SparseArray(values, kind=kind, fill_value=0)
  287. b = SparseArray(rvalues, kind=kind, fill_value=0)
  288. assert b.dtype == SparseDtype(rdtype)
  289. self._check_comparison_ops(a, b, values, rvalues)
  290. a = SparseArray(values, kind=kind, fill_value=1)
  291. b = SparseArray(rvalues, kind=kind, fill_value=2)
  292. assert b.dtype == SparseDtype(rdtype, fill_value=2)
  293. self._check_comparison_ops(a, b, values, rvalues)
  294. def test_xor(self):
  295. s = SparseArray([True, True, False, False])
  296. t = SparseArray([True, False, True, False])
  297. result = s ^ t
  298. sp_index = pd.core.arrays.sparse.IntIndex(4, np.array([0, 1, 2], dtype="int32"))
  299. expected = SparseArray([False, True, True], sparse_index=sp_index)
  300. tm.assert_sp_array_equal(result, expected)
  301. @pytest.mark.parametrize("op", [operator.eq, operator.add])
  302. def test_with_list(op):
  303. arr = SparseArray([0, 1], fill_value=0)
  304. result = op(arr, [0, 1])
  305. expected = op(arr, SparseArray([0, 1]))
  306. tm.assert_sp_array_equal(result, expected)
  307. def test_with_dataframe():
  308. # GH#27910
  309. arr = SparseArray([0, 1], fill_value=0)
  310. df = pd.DataFrame([[1, 2], [3, 4]])
  311. result = arr.__add__(df)
  312. assert result is NotImplemented
  313. def test_with_zerodim_ndarray():
  314. # GH#27910
  315. arr = SparseArray([0, 1], fill_value=0)
  316. result = arr * np.array(2)
  317. expected = arr * 2
  318. tm.assert_sp_array_equal(result, expected)
  319. @pytest.mark.parametrize("ufunc", [np.abs, np.exp])
  320. @pytest.mark.parametrize(
  321. "arr", [SparseArray([0, 0, -1, 1]), SparseArray([None, None, -1, 1])]
  322. )
  323. def test_ufuncs(ufunc, arr):
  324. result = ufunc(arr)
  325. fill_value = ufunc(arr.fill_value)
  326. expected = SparseArray(ufunc(np.asarray(arr)), fill_value=fill_value)
  327. tm.assert_sp_array_equal(result, expected)
  328. @pytest.mark.parametrize(
  329. "a, b",
  330. [
  331. (SparseArray([0, 0, 0]), np.array([0, 1, 2])),
  332. (SparseArray([0, 0, 0], fill_value=1), np.array([0, 1, 2])),
  333. (SparseArray([0, 0, 0], fill_value=1), np.array([0, 1, 2])),
  334. (SparseArray([0, 0, 0], fill_value=1), np.array([0, 1, 2])),
  335. (SparseArray([0, 0, 0], fill_value=1), np.array([0, 1, 2])),
  336. ],
  337. )
  338. @pytest.mark.parametrize("ufunc", [np.add, np.greater])
  339. def test_binary_ufuncs(ufunc, a, b):
  340. # can't say anything about fill value here.
  341. result = ufunc(a, b)
  342. expected = ufunc(np.asarray(a), np.asarray(b))
  343. assert isinstance(result, SparseArray)
  344. tm.assert_numpy_array_equal(np.asarray(result), expected)
  345. def test_ndarray_inplace():
  346. sparray = SparseArray([0, 2, 0, 0])
  347. ndarray = np.array([0, 1, 2, 3])
  348. ndarray += sparray
  349. expected = np.array([0, 3, 2, 3])
  350. tm.assert_numpy_array_equal(ndarray, expected)
  351. def test_sparray_inplace():
  352. sparray = SparseArray([0, 2, 0, 0])
  353. ndarray = np.array([0, 1, 2, 3])
  354. sparray += ndarray
  355. expected = SparseArray([0, 3, 2, 3], fill_value=0)
  356. tm.assert_sp_array_equal(sparray, expected)
  357. @pytest.mark.parametrize("cons", [list, np.array, SparseArray])
  358. def test_mismatched_length_cmp_op(cons):
  359. left = SparseArray([True, True])
  360. right = cons([True, True, True])
  361. with pytest.raises(ValueError, match="operands have mismatched length"):
  362. left & right
  363. @pytest.mark.parametrize("op", ["add", "sub", "mul", "truediv", "floordiv", "pow"])
  364. @pytest.mark.parametrize("fill_value", [np.nan, 3])
  365. def test_binary_operators(op, fill_value):
  366. op = getattr(operator, op)
  367. data1 = np.random.default_rng(2).standard_normal(20)
  368. data2 = np.random.default_rng(2).standard_normal(20)
  369. data1[::2] = fill_value
  370. data2[::3] = fill_value
  371. first = SparseArray(data1, fill_value=fill_value)
  372. second = SparseArray(data2, fill_value=fill_value)
  373. with np.errstate(all="ignore"):
  374. res = op(first, second)
  375. exp = SparseArray(
  376. op(first.to_dense(), second.to_dense()), fill_value=first.fill_value
  377. )
  378. assert isinstance(res, SparseArray)
  379. tm.assert_almost_equal(res.to_dense(), exp.to_dense())
  380. res2 = op(first, second.to_dense())
  381. assert isinstance(res2, SparseArray)
  382. tm.assert_sp_array_equal(res, res2)
  383. res3 = op(first.to_dense(), second)
  384. assert isinstance(res3, SparseArray)
  385. tm.assert_sp_array_equal(res, res3)
  386. res4 = op(first, 4)
  387. assert isinstance(res4, SparseArray)
  388. # Ignore this if the actual op raises (e.g. pow).
  389. try:
  390. exp = op(first.to_dense(), 4)
  391. exp_fv = op(first.fill_value, 4)
  392. except ValueError:
  393. pass
  394. else:
  395. tm.assert_almost_equal(res4.fill_value, exp_fv)
  396. tm.assert_almost_equal(res4.to_dense(), exp)