test_numeric.py 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480
  1. # Arithmetic tests for DataFrame/Series/Index/Array classes that should
  2. # behave identically.
  3. # Specifically for numeric dtypes
  4. from __future__ import annotations
  5. from collections import abc
  6. from datetime import timedelta
  7. from decimal import Decimal
  8. import operator
  9. import numpy as np
  10. import pytest
  11. import pandas as pd
  12. from pandas import (
  13. Index,
  14. RangeIndex,
  15. Series,
  16. Timedelta,
  17. TimedeltaIndex,
  18. array,
  19. )
  20. import pandas._testing as tm
  21. from pandas.core import ops
  22. from pandas.core.computation import expressions as expr
  23. from pandas.tests.arithmetic.common import (
  24. assert_invalid_addsub_type,
  25. assert_invalid_comparison,
  26. )
  27. @pytest.fixture(params=[Index, Series, tm.to_array])
  28. def box_pandas_1d_array(request):
  29. """
  30. Fixture to test behavior for Index, Series and tm.to_array classes
  31. """
  32. return request.param
  33. def adjust_negative_zero(zero, expected):
  34. """
  35. Helper to adjust the expected result if we are dividing by -0.0
  36. as opposed to 0.0
  37. """
  38. if np.signbit(np.array(zero)).any():
  39. # All entries in the `zero` fixture should be either
  40. # all-negative or no-negative.
  41. assert np.signbit(np.array(zero)).all()
  42. expected *= -1
  43. return expected
  44. def compare_op(series, other, op):
  45. left = np.abs(series) if op in (ops.rpow, operator.pow) else series
  46. right = np.abs(other) if op in (ops.rpow, operator.pow) else other
  47. cython_or_numpy = op(left, right)
  48. python = left.combine(right, op)
  49. if isinstance(other, Series) and not other.index.equals(series.index):
  50. python.index = python.index._with_freq(None)
  51. tm.assert_series_equal(cython_or_numpy, python)
  52. # TODO: remove this kludge once mypy stops giving false positives here
  53. # List comprehension has incompatible type List[PandasObject]; expected List[RangeIndex]
  54. # See GH#29725
  55. _ldtypes = ["i1", "i2", "i4", "i8", "u1", "u2", "u4", "u8", "f2", "f4", "f8"]
  56. lefts: list[Index | Series] = [RangeIndex(10, 40, 10)]
  57. lefts.extend([Series([10, 20, 30], dtype=dtype) for dtype in _ldtypes])
  58. lefts.extend([Index([10, 20, 30], dtype=dtype) for dtype in _ldtypes if dtype != "f2"])
  59. # ------------------------------------------------------------------
  60. # Comparisons
  61. class TestNumericComparisons:
  62. def test_operator_series_comparison_zerorank(self):
  63. # GH#13006
  64. result = np.float64(0) > Series([1, 2, 3])
  65. expected = 0.0 > Series([1, 2, 3])
  66. tm.assert_series_equal(result, expected)
  67. result = Series([1, 2, 3]) < np.float64(0)
  68. expected = Series([1, 2, 3]) < 0.0
  69. tm.assert_series_equal(result, expected)
  70. result = np.array([0, 1, 2])[0] > Series([0, 1, 2])
  71. expected = 0.0 > Series([1, 2, 3])
  72. tm.assert_series_equal(result, expected)
  73. def test_df_numeric_cmp_dt64_raises(self, box_with_array, fixed_now_ts):
  74. # GH#8932, GH#22163
  75. ts = fixed_now_ts
  76. obj = np.array(range(5))
  77. obj = tm.box_expected(obj, box_with_array)
  78. assert_invalid_comparison(obj, ts, box_with_array)
  79. def test_compare_invalid(self):
  80. # GH#8058
  81. # ops testing
  82. a = Series(np.random.randn(5), name=0)
  83. b = Series(np.random.randn(5))
  84. b.name = pd.Timestamp("2000-01-01")
  85. tm.assert_series_equal(a / b, 1 / (b / a))
  86. def test_numeric_cmp_string_numexpr_path(self, box_with_array):
  87. # GH#36377, GH#35700
  88. box = box_with_array
  89. xbox = box if box is not Index else np.ndarray
  90. obj = Series(np.random.randn(10**5))
  91. obj = tm.box_expected(obj, box, transpose=False)
  92. result = obj == "a"
  93. expected = Series(np.zeros(10**5, dtype=bool))
  94. expected = tm.box_expected(expected, xbox, transpose=False)
  95. tm.assert_equal(result, expected)
  96. result = obj != "a"
  97. tm.assert_equal(result, ~expected)
  98. msg = "Invalid comparison between dtype=float64 and str"
  99. with pytest.raises(TypeError, match=msg):
  100. obj < "a"
  101. # ------------------------------------------------------------------
  102. # Numeric dtypes Arithmetic with Datetime/Timedelta Scalar
  103. class TestNumericArraylikeArithmeticWithDatetimeLike:
  104. @pytest.mark.parametrize("box_cls", [np.array, Index, Series])
  105. @pytest.mark.parametrize(
  106. "left", lefts, ids=lambda x: type(x).__name__ + str(x.dtype)
  107. )
  108. def test_mul_td64arr(self, left, box_cls):
  109. # GH#22390
  110. right = np.array([1, 2, 3], dtype="m8[s]")
  111. right = box_cls(right)
  112. expected = TimedeltaIndex(["10s", "40s", "90s"], dtype=right.dtype)
  113. if isinstance(left, Series) or box_cls is Series:
  114. expected = Series(expected)
  115. assert expected.dtype == right.dtype
  116. result = left * right
  117. tm.assert_equal(result, expected)
  118. result = right * left
  119. tm.assert_equal(result, expected)
  120. @pytest.mark.parametrize("box_cls", [np.array, Index, Series])
  121. @pytest.mark.parametrize(
  122. "left", lefts, ids=lambda x: type(x).__name__ + str(x.dtype)
  123. )
  124. def test_div_td64arr(self, left, box_cls):
  125. # GH#22390
  126. right = np.array([10, 40, 90], dtype="m8[s]")
  127. right = box_cls(right)
  128. expected = TimedeltaIndex(["1s", "2s", "3s"], dtype=right.dtype)
  129. if isinstance(left, Series) or box_cls is Series:
  130. expected = Series(expected)
  131. assert expected.dtype == right.dtype
  132. result = right / left
  133. tm.assert_equal(result, expected)
  134. result = right // left
  135. tm.assert_equal(result, expected)
  136. # (true_) needed for min-versions build 2022-12-26
  137. msg = "ufunc '(true_)?divide' cannot use operands with types"
  138. with pytest.raises(TypeError, match=msg):
  139. left / right
  140. msg = "ufunc 'floor_divide' cannot use operands with types"
  141. with pytest.raises(TypeError, match=msg):
  142. left // right
  143. # TODO: also test Tick objects;
  144. # see test_numeric_arr_rdiv_tdscalar for note on these failing
  145. @pytest.mark.parametrize(
  146. "scalar_td",
  147. [
  148. Timedelta(days=1),
  149. Timedelta(days=1).to_timedelta64(),
  150. Timedelta(days=1).to_pytimedelta(),
  151. Timedelta(days=1).to_timedelta64().astype("timedelta64[s]"),
  152. Timedelta(days=1).to_timedelta64().astype("timedelta64[ms]"),
  153. ],
  154. ids=lambda x: type(x).__name__,
  155. )
  156. def test_numeric_arr_mul_tdscalar(self, scalar_td, numeric_idx, box_with_array):
  157. # GH#19333
  158. box = box_with_array
  159. index = numeric_idx
  160. expected = TimedeltaIndex([Timedelta(days=n) for n in range(len(index))])
  161. if isinstance(scalar_td, np.timedelta64):
  162. dtype = scalar_td.dtype
  163. expected = expected.astype(dtype)
  164. elif type(scalar_td) is timedelta:
  165. expected = expected.astype("m8[us]")
  166. index = tm.box_expected(index, box)
  167. expected = tm.box_expected(expected, box)
  168. result = index * scalar_td
  169. tm.assert_equal(result, expected)
  170. commute = scalar_td * index
  171. tm.assert_equal(commute, expected)
  172. @pytest.mark.parametrize(
  173. "scalar_td",
  174. [
  175. Timedelta(days=1),
  176. Timedelta(days=1).to_timedelta64(),
  177. Timedelta(days=1).to_pytimedelta(),
  178. ],
  179. ids=lambda x: type(x).__name__,
  180. )
  181. @pytest.mark.parametrize("dtype", [np.int64, np.float64])
  182. def test_numeric_arr_mul_tdscalar_numexpr_path(
  183. self, dtype, scalar_td, box_with_array
  184. ):
  185. # GH#44772 for the float64 case
  186. box = box_with_array
  187. arr_i8 = np.arange(2 * 10**4).astype(np.int64, copy=False)
  188. arr = arr_i8.astype(dtype, copy=False)
  189. obj = tm.box_expected(arr, box, transpose=False)
  190. expected = arr_i8.view("timedelta64[D]").astype("timedelta64[ns]")
  191. if type(scalar_td) is timedelta:
  192. expected = expected.astype("timedelta64[us]")
  193. expected = tm.box_expected(expected, box, transpose=False)
  194. result = obj * scalar_td
  195. tm.assert_equal(result, expected)
  196. result = scalar_td * obj
  197. tm.assert_equal(result, expected)
  198. def test_numeric_arr_rdiv_tdscalar(self, three_days, numeric_idx, box_with_array):
  199. box = box_with_array
  200. index = numeric_idx[1:3]
  201. expected = TimedeltaIndex(["3 Days", "36 Hours"])
  202. if isinstance(three_days, np.timedelta64):
  203. dtype = three_days.dtype
  204. if dtype < np.dtype("m8[s]"):
  205. # i.e. resolution is lower -> use lowest supported resolution
  206. dtype = np.dtype("m8[s]")
  207. expected = expected.astype(dtype)
  208. elif type(three_days) is timedelta:
  209. expected = expected.astype("m8[us]")
  210. index = tm.box_expected(index, box)
  211. expected = tm.box_expected(expected, box)
  212. result = three_days / index
  213. tm.assert_equal(result, expected)
  214. msg = "cannot use operands with types dtype"
  215. with pytest.raises(TypeError, match=msg):
  216. index / three_days
  217. @pytest.mark.parametrize(
  218. "other",
  219. [
  220. Timedelta(hours=31),
  221. Timedelta(hours=31).to_pytimedelta(),
  222. Timedelta(hours=31).to_timedelta64(),
  223. Timedelta(hours=31).to_timedelta64().astype("m8[h]"),
  224. np.timedelta64("NaT"),
  225. np.timedelta64("NaT", "D"),
  226. pd.offsets.Minute(3),
  227. pd.offsets.Second(0),
  228. # GH#28080 numeric+datetimelike should raise; Timestamp used
  229. # to raise NullFrequencyError but that behavior was removed in 1.0
  230. pd.Timestamp("2021-01-01", tz="Asia/Tokyo"),
  231. pd.Timestamp("2021-01-01"),
  232. pd.Timestamp("2021-01-01").to_pydatetime(),
  233. pd.Timestamp("2021-01-01", tz="UTC").to_pydatetime(),
  234. pd.Timestamp("2021-01-01").to_datetime64(),
  235. np.datetime64("NaT", "ns"),
  236. pd.NaT,
  237. ],
  238. ids=repr,
  239. )
  240. def test_add_sub_datetimedeltalike_invalid(
  241. self, numeric_idx, other, box_with_array
  242. ):
  243. box = box_with_array
  244. left = tm.box_expected(numeric_idx, box)
  245. msg = "|".join(
  246. [
  247. "unsupported operand type",
  248. "Addition/subtraction of integers and integer-arrays",
  249. "Instead of adding/subtracting",
  250. "cannot use operands with types dtype",
  251. "Concatenation operation is not implemented for NumPy arrays",
  252. "Cannot (add|subtract) NaT (to|from) ndarray",
  253. # pd.array vs np.datetime64 case
  254. r"operand type\(s\) all returned NotImplemented from __array_ufunc__",
  255. "can only perform ops with numeric values",
  256. "cannot subtract DatetimeArray from ndarray",
  257. # pd.Timedelta(1) + Index([0, 1, 2])
  258. "Cannot add or subtract Timedelta from integers",
  259. ]
  260. )
  261. assert_invalid_addsub_type(left, other, msg)
  262. # ------------------------------------------------------------------
  263. # Arithmetic
  264. class TestDivisionByZero:
  265. def test_div_zero(self, zero, numeric_idx):
  266. idx = numeric_idx
  267. expected = Index([np.nan, np.inf, np.inf, np.inf, np.inf], dtype=np.float64)
  268. # We only adjust for Index, because Series does not yet apply
  269. # the adjustment correctly.
  270. expected2 = adjust_negative_zero(zero, expected)
  271. result = idx / zero
  272. tm.assert_index_equal(result, expected2)
  273. ser_compat = Series(idx).astype("i8") / np.array(zero).astype("i8")
  274. tm.assert_series_equal(ser_compat, Series(expected))
  275. def test_floordiv_zero(self, zero, numeric_idx):
  276. idx = numeric_idx
  277. expected = Index([np.nan, np.inf, np.inf, np.inf, np.inf], dtype=np.float64)
  278. # We only adjust for Index, because Series does not yet apply
  279. # the adjustment correctly.
  280. expected2 = adjust_negative_zero(zero, expected)
  281. result = idx // zero
  282. tm.assert_index_equal(result, expected2)
  283. ser_compat = Series(idx).astype("i8") // np.array(zero).astype("i8")
  284. tm.assert_series_equal(ser_compat, Series(expected))
  285. def test_mod_zero(self, zero, numeric_idx):
  286. idx = numeric_idx
  287. expected = Index([np.nan, np.nan, np.nan, np.nan, np.nan], dtype=np.float64)
  288. result = idx % zero
  289. tm.assert_index_equal(result, expected)
  290. ser_compat = Series(idx).astype("i8") % np.array(zero).astype("i8")
  291. tm.assert_series_equal(ser_compat, Series(result))
  292. def test_divmod_zero(self, zero, numeric_idx):
  293. idx = numeric_idx
  294. exleft = Index([np.nan, np.inf, np.inf, np.inf, np.inf], dtype=np.float64)
  295. exright = Index([np.nan, np.nan, np.nan, np.nan, np.nan], dtype=np.float64)
  296. exleft = adjust_negative_zero(zero, exleft)
  297. result = divmod(idx, zero)
  298. tm.assert_index_equal(result[0], exleft)
  299. tm.assert_index_equal(result[1], exright)
  300. @pytest.mark.parametrize("op", [operator.truediv, operator.floordiv])
  301. def test_div_negative_zero(self, zero, numeric_idx, op):
  302. # Check that -1 / -0.0 returns np.inf, not -np.inf
  303. if numeric_idx.dtype == np.uint64:
  304. return
  305. idx = numeric_idx - 3
  306. expected = Index([-np.inf, -np.inf, -np.inf, np.nan, np.inf], dtype=np.float64)
  307. expected = adjust_negative_zero(zero, expected)
  308. result = op(idx, zero)
  309. tm.assert_index_equal(result, expected)
  310. # ------------------------------------------------------------------
  311. @pytest.mark.parametrize("dtype1", [np.int64, np.float64, np.uint64])
  312. def test_ser_div_ser(
  313. self,
  314. switch_numexpr_min_elements,
  315. dtype1,
  316. any_real_numpy_dtype,
  317. ):
  318. # no longer do integer div for any ops, but deal with the 0's
  319. dtype2 = any_real_numpy_dtype
  320. first = Series([3, 4, 5, 8], name="first").astype(dtype1)
  321. second = Series([0, 0, 0, 3], name="second").astype(dtype2)
  322. with np.errstate(all="ignore"):
  323. expected = Series(
  324. first.values.astype(np.float64) / second.values,
  325. dtype="float64",
  326. name=None,
  327. )
  328. expected.iloc[0:3] = np.inf
  329. if first.dtype == "int64" and second.dtype == "float32":
  330. # when using numexpr, the casting rules are slightly different
  331. # and int64/float32 combo results in float32 instead of float64
  332. if expr.USE_NUMEXPR and switch_numexpr_min_elements == 0:
  333. expected = expected.astype("float32")
  334. result = first / second
  335. tm.assert_series_equal(result, expected)
  336. assert not result.equals(second / first)
  337. @pytest.mark.parametrize("dtype1", [np.int64, np.float64, np.uint64])
  338. def test_ser_divmod_zero(self, dtype1, any_real_numpy_dtype):
  339. # GH#26987
  340. dtype2 = any_real_numpy_dtype
  341. left = Series([1, 1]).astype(dtype1)
  342. right = Series([0, 2]).astype(dtype2)
  343. # GH#27321 pandas convention is to set 1 // 0 to np.inf, as opposed
  344. # to numpy which sets to np.nan; patch `expected[0]` below
  345. expected = left // right, left % right
  346. expected = list(expected)
  347. expected[0] = expected[0].astype(np.float64)
  348. expected[0][0] = np.inf
  349. result = divmod(left, right)
  350. tm.assert_series_equal(result[0], expected[0])
  351. tm.assert_series_equal(result[1], expected[1])
  352. # rdivmod case
  353. result = divmod(left.values, right)
  354. tm.assert_series_equal(result[0], expected[0])
  355. tm.assert_series_equal(result[1], expected[1])
  356. def test_ser_divmod_inf(self):
  357. left = Series([np.inf, 1.0])
  358. right = Series([np.inf, 2.0])
  359. expected = left // right, left % right
  360. result = divmod(left, right)
  361. tm.assert_series_equal(result[0], expected[0])
  362. tm.assert_series_equal(result[1], expected[1])
  363. # rdivmod case
  364. result = divmod(left.values, right)
  365. tm.assert_series_equal(result[0], expected[0])
  366. tm.assert_series_equal(result[1], expected[1])
  367. def test_rdiv_zero_compat(self):
  368. # GH#8674
  369. zero_array = np.array([0] * 5)
  370. data = np.random.randn(5)
  371. expected = Series([0.0] * 5)
  372. result = zero_array / Series(data)
  373. tm.assert_series_equal(result, expected)
  374. result = Series(zero_array) / data
  375. tm.assert_series_equal(result, expected)
  376. result = Series(zero_array) / Series(data)
  377. tm.assert_series_equal(result, expected)
  378. def test_div_zero_inf_signs(self):
  379. # GH#9144, inf signing
  380. ser = Series([-1, 0, 1], name="first")
  381. expected = Series([-np.inf, np.nan, np.inf], name="first")
  382. result = ser / 0
  383. tm.assert_series_equal(result, expected)
  384. def test_rdiv_zero(self):
  385. # GH#9144
  386. ser = Series([-1, 0, 1], name="first")
  387. expected = Series([0.0, np.nan, 0.0], name="first")
  388. result = 0 / ser
  389. tm.assert_series_equal(result, expected)
  390. def test_floordiv_div(self):
  391. # GH#9144
  392. ser = Series([-1, 0, 1], name="first")
  393. result = ser // 0
  394. expected = Series([-np.inf, np.nan, np.inf], name="first")
  395. tm.assert_series_equal(result, expected)
  396. def test_df_div_zero_df(self):
  397. # integer div, but deal with the 0's (GH#9144)
  398. df = pd.DataFrame({"first": [3, 4, 5, 8], "second": [0, 0, 0, 3]})
  399. result = df / df
  400. first = Series([1.0, 1.0, 1.0, 1.0])
  401. second = Series([np.nan, np.nan, np.nan, 1])
  402. expected = pd.DataFrame({"first": first, "second": second})
  403. tm.assert_frame_equal(result, expected)
  404. def test_df_div_zero_array(self):
  405. # integer div, but deal with the 0's (GH#9144)
  406. df = pd.DataFrame({"first": [3, 4, 5, 8], "second": [0, 0, 0, 3]})
  407. first = Series([1.0, 1.0, 1.0, 1.0])
  408. second = Series([np.nan, np.nan, np.nan, 1])
  409. expected = pd.DataFrame({"first": first, "second": second})
  410. with np.errstate(all="ignore"):
  411. arr = df.values.astype("float") / df.values
  412. result = pd.DataFrame(arr, index=df.index, columns=df.columns)
  413. tm.assert_frame_equal(result, expected)
  414. def test_df_div_zero_int(self):
  415. # integer div, but deal with the 0's (GH#9144)
  416. df = pd.DataFrame({"first": [3, 4, 5, 8], "second": [0, 0, 0, 3]})
  417. result = df / 0
  418. expected = pd.DataFrame(np.inf, index=df.index, columns=df.columns)
  419. expected.iloc[0:3, 1] = np.nan
  420. tm.assert_frame_equal(result, expected)
  421. # numpy has a slightly different (wrong) treatment
  422. with np.errstate(all="ignore"):
  423. arr = df.values.astype("float64") / 0
  424. result2 = pd.DataFrame(arr, index=df.index, columns=df.columns)
  425. tm.assert_frame_equal(result2, expected)
  426. def test_df_div_zero_series_does_not_commute(self):
  427. # integer div, but deal with the 0's (GH#9144)
  428. df = pd.DataFrame(np.random.randn(10, 5))
  429. ser = df[0]
  430. res = ser / df
  431. res2 = df / ser
  432. assert not res.fillna(0).equals(res2.fillna(0))
  433. # ------------------------------------------------------------------
  434. # Mod By Zero
  435. def test_df_mod_zero_df(self, using_array_manager):
  436. # GH#3590, modulo as ints
  437. df = pd.DataFrame({"first": [3, 4, 5, 8], "second": [0, 0, 0, 3]})
  438. # this is technically wrong, as the integer portion is coerced to float
  439. first = Series([0, 0, 0, 0])
  440. if not using_array_manager:
  441. # INFO(ArrayManager) BlockManager doesn't preserve dtype per column
  442. # while ArrayManager performs op column-wisedoes and thus preserves
  443. # dtype if possible
  444. first = first.astype("float64")
  445. second = Series([np.nan, np.nan, np.nan, 0])
  446. expected = pd.DataFrame({"first": first, "second": second})
  447. result = df % df
  448. tm.assert_frame_equal(result, expected)
  449. # GH#38939 If we dont pass copy=False, df is consolidated and
  450. # result["first"] is float64 instead of int64
  451. df = pd.DataFrame({"first": [3, 4, 5, 8], "second": [0, 0, 0, 3]}, copy=False)
  452. first = Series([0, 0, 0, 0], dtype="int64")
  453. second = Series([np.nan, np.nan, np.nan, 0])
  454. expected = pd.DataFrame({"first": first, "second": second})
  455. result = df % df
  456. tm.assert_frame_equal(result, expected)
  457. def test_df_mod_zero_array(self):
  458. # GH#3590, modulo as ints
  459. df = pd.DataFrame({"first": [3, 4, 5, 8], "second": [0, 0, 0, 3]})
  460. # this is technically wrong, as the integer portion is coerced to float
  461. # ###
  462. first = Series([0, 0, 0, 0], dtype="float64")
  463. second = Series([np.nan, np.nan, np.nan, 0])
  464. expected = pd.DataFrame({"first": first, "second": second})
  465. # numpy has a slightly different (wrong) treatment
  466. with np.errstate(all="ignore"):
  467. arr = df.values % df.values
  468. result2 = pd.DataFrame(arr, index=df.index, columns=df.columns, dtype="float64")
  469. result2.iloc[0:3, 1] = np.nan
  470. tm.assert_frame_equal(result2, expected)
  471. def test_df_mod_zero_int(self):
  472. # GH#3590, modulo as ints
  473. df = pd.DataFrame({"first": [3, 4, 5, 8], "second": [0, 0, 0, 3]})
  474. result = df % 0
  475. expected = pd.DataFrame(np.nan, index=df.index, columns=df.columns)
  476. tm.assert_frame_equal(result, expected)
  477. # numpy has a slightly different (wrong) treatment
  478. with np.errstate(all="ignore"):
  479. arr = df.values.astype("float64") % 0
  480. result2 = pd.DataFrame(arr, index=df.index, columns=df.columns)
  481. tm.assert_frame_equal(result2, expected)
  482. def test_df_mod_zero_series_does_not_commute(self):
  483. # GH#3590, modulo as ints
  484. # not commutative with series
  485. df = pd.DataFrame(np.random.randn(10, 5))
  486. ser = df[0]
  487. res = ser % df
  488. res2 = df % ser
  489. assert not res.fillna(0).equals(res2.fillna(0))
  490. class TestMultiplicationDivision:
  491. # __mul__, __rmul__, __div__, __rdiv__, __floordiv__, __rfloordiv__
  492. # for non-timestamp/timedelta/period dtypes
  493. def test_divide_decimal(self, box_with_array):
  494. # resolves issue GH#9787
  495. box = box_with_array
  496. ser = Series([Decimal(10)])
  497. expected = Series([Decimal(5)])
  498. ser = tm.box_expected(ser, box)
  499. expected = tm.box_expected(expected, box)
  500. result = ser / Decimal(2)
  501. tm.assert_equal(result, expected)
  502. result = ser // Decimal(2)
  503. tm.assert_equal(result, expected)
  504. def test_div_equiv_binop(self):
  505. # Test Series.div as well as Series.__div__
  506. # float/integer issue
  507. # GH#7785
  508. first = Series([1, 0], name="first")
  509. second = Series([-0.01, -0.02], name="second")
  510. expected = Series([-0.01, -np.inf])
  511. result = second.div(first)
  512. tm.assert_series_equal(result, expected, check_names=False)
  513. result = second / first
  514. tm.assert_series_equal(result, expected)
  515. def test_div_int(self, numeric_idx):
  516. idx = numeric_idx
  517. result = idx / 1
  518. expected = idx.astype("float64")
  519. tm.assert_index_equal(result, expected)
  520. result = idx / 2
  521. expected = Index(idx.values / 2)
  522. tm.assert_index_equal(result, expected)
  523. @pytest.mark.parametrize("op", [operator.mul, ops.rmul, operator.floordiv])
  524. def test_mul_int_identity(self, op, numeric_idx, box_with_array):
  525. idx = numeric_idx
  526. idx = tm.box_expected(idx, box_with_array)
  527. result = op(idx, 1)
  528. tm.assert_equal(result, idx)
  529. def test_mul_int_array(self, numeric_idx):
  530. idx = numeric_idx
  531. didx = idx * idx
  532. result = idx * np.array(5, dtype="int64")
  533. tm.assert_index_equal(result, idx * 5)
  534. arr_dtype = "uint64" if idx.dtype == np.uint64 else "int64"
  535. result = idx * np.arange(5, dtype=arr_dtype)
  536. tm.assert_index_equal(result, didx)
  537. def test_mul_int_series(self, numeric_idx):
  538. idx = numeric_idx
  539. didx = idx * idx
  540. arr_dtype = "uint64" if idx.dtype == np.uint64 else "int64"
  541. result = idx * Series(np.arange(5, dtype=arr_dtype))
  542. tm.assert_series_equal(result, Series(didx))
  543. def test_mul_float_series(self, numeric_idx):
  544. idx = numeric_idx
  545. rng5 = np.arange(5, dtype="float64")
  546. result = idx * Series(rng5 + 0.1)
  547. expected = Series(rng5 * (rng5 + 0.1))
  548. tm.assert_series_equal(result, expected)
  549. def test_mul_index(self, numeric_idx):
  550. idx = numeric_idx
  551. result = idx * idx
  552. tm.assert_index_equal(result, idx**2)
  553. def test_mul_datelike_raises(self, numeric_idx):
  554. idx = numeric_idx
  555. msg = "cannot perform __rmul__ with this index type"
  556. with pytest.raises(TypeError, match=msg):
  557. idx * pd.date_range("20130101", periods=5)
  558. def test_mul_size_mismatch_raises(self, numeric_idx):
  559. idx = numeric_idx
  560. msg = "operands could not be broadcast together"
  561. with pytest.raises(ValueError, match=msg):
  562. idx * idx[0:3]
  563. with pytest.raises(ValueError, match=msg):
  564. idx * np.array([1, 2])
  565. @pytest.mark.parametrize("op", [operator.pow, ops.rpow])
  566. def test_pow_float(self, op, numeric_idx, box_with_array):
  567. # test power calculations both ways, GH#14973
  568. box = box_with_array
  569. idx = numeric_idx
  570. expected = Index(op(idx.values, 2.0))
  571. idx = tm.box_expected(idx, box)
  572. expected = tm.box_expected(expected, box)
  573. result = op(idx, 2.0)
  574. tm.assert_equal(result, expected)
  575. def test_modulo(self, numeric_idx, box_with_array):
  576. # GH#9244
  577. box = box_with_array
  578. idx = numeric_idx
  579. expected = Index(idx.values % 2)
  580. idx = tm.box_expected(idx, box)
  581. expected = tm.box_expected(expected, box)
  582. result = idx % 2
  583. tm.assert_equal(result, expected)
  584. def test_divmod_scalar(self, numeric_idx):
  585. idx = numeric_idx
  586. result = divmod(idx, 2)
  587. with np.errstate(all="ignore"):
  588. div, mod = divmod(idx.values, 2)
  589. expected = Index(div), Index(mod)
  590. for r, e in zip(result, expected):
  591. tm.assert_index_equal(r, e)
  592. def test_divmod_ndarray(self, numeric_idx):
  593. idx = numeric_idx
  594. other = np.ones(idx.values.shape, dtype=idx.values.dtype) * 2
  595. result = divmod(idx, other)
  596. with np.errstate(all="ignore"):
  597. div, mod = divmod(idx.values, other)
  598. expected = Index(div), Index(mod)
  599. for r, e in zip(result, expected):
  600. tm.assert_index_equal(r, e)
  601. def test_divmod_series(self, numeric_idx):
  602. idx = numeric_idx
  603. other = np.ones(idx.values.shape, dtype=idx.values.dtype) * 2
  604. result = divmod(idx, Series(other))
  605. with np.errstate(all="ignore"):
  606. div, mod = divmod(idx.values, other)
  607. expected = Series(div), Series(mod)
  608. for r, e in zip(result, expected):
  609. tm.assert_series_equal(r, e)
  610. @pytest.mark.parametrize("other", [np.nan, 7, -23, 2.718, -3.14, np.inf])
  611. def test_ops_np_scalar(self, other):
  612. vals = np.random.randn(5, 3)
  613. f = lambda x: pd.DataFrame(
  614. x, index=list("ABCDE"), columns=["jim", "joe", "jolie"]
  615. )
  616. df = f(vals)
  617. tm.assert_frame_equal(df / np.array(other), f(vals / other))
  618. tm.assert_frame_equal(np.array(other) * df, f(vals * other))
  619. tm.assert_frame_equal(df + np.array(other), f(vals + other))
  620. tm.assert_frame_equal(np.array(other) - df, f(other - vals))
  621. # TODO: This came from series.test.test_operators, needs cleanup
  622. def test_operators_frame(self):
  623. # rpow does not work with DataFrame
  624. ts = tm.makeTimeSeries()
  625. ts.name = "ts"
  626. df = pd.DataFrame({"A": ts})
  627. tm.assert_series_equal(ts + ts, ts + df["A"], check_names=False)
  628. tm.assert_series_equal(ts**ts, ts ** df["A"], check_names=False)
  629. tm.assert_series_equal(ts < ts, ts < df["A"], check_names=False)
  630. tm.assert_series_equal(ts / ts, ts / df["A"], check_names=False)
  631. # TODO: this came from tests.series.test_analytics, needs cleanup and
  632. # de-duplication with test_modulo above
  633. def test_modulo2(self):
  634. with np.errstate(all="ignore"):
  635. # GH#3590, modulo as ints
  636. p = pd.DataFrame({"first": [3, 4, 5, 8], "second": [0, 0, 0, 3]})
  637. result = p["first"] % p["second"]
  638. expected = Series(p["first"].values % p["second"].values, dtype="float64")
  639. expected.iloc[0:3] = np.nan
  640. tm.assert_series_equal(result, expected)
  641. result = p["first"] % 0
  642. expected = Series(np.nan, index=p.index, name="first")
  643. tm.assert_series_equal(result, expected)
  644. p = p.astype("float64")
  645. result = p["first"] % p["second"]
  646. expected = Series(p["first"].values % p["second"].values)
  647. tm.assert_series_equal(result, expected)
  648. p = p.astype("float64")
  649. result = p["first"] % p["second"]
  650. result2 = p["second"] % p["first"]
  651. assert not result.equals(result2)
  652. def test_modulo_zero_int(self):
  653. # GH#9144
  654. with np.errstate(all="ignore"):
  655. s = Series([0, 1])
  656. result = s % 0
  657. expected = Series([np.nan, np.nan])
  658. tm.assert_series_equal(result, expected)
  659. result = 0 % s
  660. expected = Series([np.nan, 0.0])
  661. tm.assert_series_equal(result, expected)
  662. class TestAdditionSubtraction:
  663. # __add__, __sub__, __radd__, __rsub__, __iadd__, __isub__
  664. # for non-timestamp/timedelta/period dtypes
  665. @pytest.mark.parametrize(
  666. "first, second, expected",
  667. [
  668. (
  669. Series([1, 2, 3], index=list("ABC"), name="x"),
  670. Series([2, 2, 2], index=list("ABD"), name="x"),
  671. Series([3.0, 4.0, np.nan, np.nan], index=list("ABCD"), name="x"),
  672. ),
  673. (
  674. Series([1, 2, 3], index=list("ABC"), name="x"),
  675. Series([2, 2, 2, 2], index=list("ABCD"), name="x"),
  676. Series([3, 4, 5, np.nan], index=list("ABCD"), name="x"),
  677. ),
  678. ],
  679. )
  680. def test_add_series(self, first, second, expected):
  681. # GH#1134
  682. tm.assert_series_equal(first + second, expected)
  683. tm.assert_series_equal(second + first, expected)
  684. @pytest.mark.parametrize(
  685. "first, second, expected",
  686. [
  687. (
  688. pd.DataFrame({"x": [1, 2, 3]}, index=list("ABC")),
  689. pd.DataFrame({"x": [2, 2, 2]}, index=list("ABD")),
  690. pd.DataFrame({"x": [3.0, 4.0, np.nan, np.nan]}, index=list("ABCD")),
  691. ),
  692. (
  693. pd.DataFrame({"x": [1, 2, 3]}, index=list("ABC")),
  694. pd.DataFrame({"x": [2, 2, 2, 2]}, index=list("ABCD")),
  695. pd.DataFrame({"x": [3, 4, 5, np.nan]}, index=list("ABCD")),
  696. ),
  697. ],
  698. )
  699. def test_add_frames(self, first, second, expected):
  700. # GH#1134
  701. tm.assert_frame_equal(first + second, expected)
  702. tm.assert_frame_equal(second + first, expected)
  703. # TODO: This came from series.test.test_operators, needs cleanup
  704. def test_series_frame_radd_bug(self, fixed_now_ts):
  705. # GH#353
  706. vals = Series(tm.rands_array(5, 10))
  707. result = "foo_" + vals
  708. expected = vals.map(lambda x: "foo_" + x)
  709. tm.assert_series_equal(result, expected)
  710. frame = pd.DataFrame({"vals": vals})
  711. result = "foo_" + frame
  712. expected = pd.DataFrame({"vals": vals.map(lambda x: "foo_" + x)})
  713. tm.assert_frame_equal(result, expected)
  714. ts = tm.makeTimeSeries()
  715. ts.name = "ts"
  716. # really raise this time
  717. fix_now = fixed_now_ts.to_pydatetime()
  718. msg = "|".join(
  719. [
  720. "unsupported operand type",
  721. # wrong error message, see https://github.com/numpy/numpy/issues/18832
  722. "Concatenation operation",
  723. ]
  724. )
  725. with pytest.raises(TypeError, match=msg):
  726. fix_now + ts
  727. with pytest.raises(TypeError, match=msg):
  728. ts + fix_now
  729. # TODO: This came from series.test.test_operators, needs cleanup
  730. def test_datetime64_with_index(self):
  731. # arithmetic integer ops with an index
  732. ser = Series(np.random.randn(5))
  733. expected = ser - ser.index.to_series()
  734. result = ser - ser.index
  735. tm.assert_series_equal(result, expected)
  736. # GH#4629
  737. # arithmetic datetime64 ops with an index
  738. ser = Series(
  739. pd.date_range("20130101", periods=5),
  740. index=pd.date_range("20130101", periods=5),
  741. )
  742. expected = ser - ser.index.to_series()
  743. result = ser - ser.index
  744. tm.assert_series_equal(result, expected)
  745. msg = "cannot subtract PeriodArray from DatetimeArray"
  746. with pytest.raises(TypeError, match=msg):
  747. # GH#18850
  748. result = ser - ser.index.to_period()
  749. df = pd.DataFrame(
  750. np.random.randn(5, 2), index=pd.date_range("20130101", periods=5)
  751. )
  752. df["date"] = pd.Timestamp("20130102")
  753. df["expected"] = df["date"] - df.index.to_series()
  754. df["result"] = df["date"] - df.index
  755. tm.assert_series_equal(df["result"], df["expected"], check_names=False)
  756. # TODO: taken from tests.frame.test_operators, needs cleanup
  757. def test_frame_operators(self, float_frame):
  758. frame = float_frame
  759. garbage = np.random.random(4)
  760. colSeries = Series(garbage, index=np.array(frame.columns))
  761. idSum = frame + frame
  762. seriesSum = frame + colSeries
  763. for col, series in idSum.items():
  764. for idx, val in series.items():
  765. origVal = frame[col][idx] * 2
  766. if not np.isnan(val):
  767. assert val == origVal
  768. else:
  769. assert np.isnan(origVal)
  770. for col, series in seriesSum.items():
  771. for idx, val in series.items():
  772. origVal = frame[col][idx] + colSeries[col]
  773. if not np.isnan(val):
  774. assert val == origVal
  775. else:
  776. assert np.isnan(origVal)
  777. def test_frame_operators_col_align(self, float_frame):
  778. frame2 = pd.DataFrame(float_frame, columns=["D", "C", "B", "A"])
  779. added = frame2 + frame2
  780. expected = frame2 * 2
  781. tm.assert_frame_equal(added, expected)
  782. def test_frame_operators_none_to_nan(self):
  783. df = pd.DataFrame({"a": ["a", None, "b"]})
  784. tm.assert_frame_equal(df + df, pd.DataFrame({"a": ["aa", np.nan, "bb"]}))
  785. @pytest.mark.parametrize("dtype", ("float", "int64"))
  786. def test_frame_operators_empty_like(self, dtype):
  787. # Test for issue #10181
  788. frames = [
  789. pd.DataFrame(dtype=dtype),
  790. pd.DataFrame(columns=["A"], dtype=dtype),
  791. pd.DataFrame(index=[0], dtype=dtype),
  792. ]
  793. for df in frames:
  794. assert (df + df).equals(df)
  795. tm.assert_frame_equal(df + df, df)
  796. @pytest.mark.parametrize(
  797. "func",
  798. [lambda x: x * 2, lambda x: x[::2], lambda x: 5],
  799. ids=["multiply", "slice", "constant"],
  800. )
  801. def test_series_operators_arithmetic(self, all_arithmetic_functions, func):
  802. op = all_arithmetic_functions
  803. series = tm.makeTimeSeries().rename("ts")
  804. other = func(series)
  805. compare_op(series, other, op)
  806. @pytest.mark.parametrize(
  807. "func", [lambda x: x + 1, lambda x: 5], ids=["add", "constant"]
  808. )
  809. def test_series_operators_compare(self, comparison_op, func):
  810. op = comparison_op
  811. series = tm.makeTimeSeries().rename("ts")
  812. other = func(series)
  813. compare_op(series, other, op)
  814. @pytest.mark.parametrize(
  815. "func",
  816. [lambda x: x * 2, lambda x: x[::2], lambda x: 5],
  817. ids=["multiply", "slice", "constant"],
  818. )
  819. def test_divmod(self, func):
  820. series = tm.makeTimeSeries().rename("ts")
  821. other = func(series)
  822. results = divmod(series, other)
  823. if isinstance(other, abc.Iterable) and len(series) != len(other):
  824. # if the lengths don't match, this is the test where we use
  825. # `tser[::2]`. Pad every other value in `other_np` with nan.
  826. other_np = []
  827. for n in other:
  828. other_np.append(n)
  829. other_np.append(np.nan)
  830. else:
  831. other_np = other
  832. other_np = np.asarray(other_np)
  833. with np.errstate(all="ignore"):
  834. expecteds = divmod(series.values, np.asarray(other_np))
  835. for result, expected in zip(results, expecteds):
  836. # check the values, name, and index separately
  837. tm.assert_almost_equal(np.asarray(result), expected)
  838. assert result.name == series.name
  839. tm.assert_index_equal(result.index, series.index._with_freq(None))
  840. def test_series_divmod_zero(self):
  841. # Check that divmod uses pandas convention for division by zero,
  842. # which does not match numpy.
  843. # pandas convention has
  844. # 1/0 == np.inf
  845. # -1/0 == -np.inf
  846. # 1/-0.0 == -np.inf
  847. # -1/-0.0 == np.inf
  848. tser = tm.makeTimeSeries().rename("ts")
  849. other = tser * 0
  850. result = divmod(tser, other)
  851. exp1 = Series([np.inf] * len(tser), index=tser.index, name="ts")
  852. exp2 = Series([np.nan] * len(tser), index=tser.index, name="ts")
  853. tm.assert_series_equal(result[0], exp1)
  854. tm.assert_series_equal(result[1], exp2)
  855. class TestUFuncCompat:
  856. # TODO: add more dtypes
  857. @pytest.mark.parametrize("holder", [Index, RangeIndex, Series])
  858. @pytest.mark.parametrize("dtype", [np.int64, np.uint64, np.float64])
  859. def test_ufunc_compat(self, holder, dtype):
  860. box = Series if holder is Series else Index
  861. if holder is RangeIndex:
  862. if dtype != np.int64:
  863. pytest.skip(f"dtype {dtype} not relevant for RangeIndex")
  864. idx = RangeIndex(0, 5, name="foo")
  865. else:
  866. idx = holder(np.arange(5, dtype=dtype), name="foo")
  867. result = np.sin(idx)
  868. expected = box(np.sin(np.arange(5, dtype=dtype)), name="foo")
  869. tm.assert_equal(result, expected)
  870. # TODO: add more dtypes
  871. @pytest.mark.parametrize("holder", [Index, Series])
  872. @pytest.mark.parametrize("dtype", [np.int64, np.uint64, np.float64])
  873. def test_ufunc_coercions(self, holder, dtype):
  874. idx = holder([1, 2, 3, 4, 5], dtype=dtype, name="x")
  875. box = Series if holder is Series else Index
  876. result = np.sqrt(idx)
  877. assert result.dtype == "f8" and isinstance(result, box)
  878. exp = Index(np.sqrt(np.array([1, 2, 3, 4, 5], dtype=np.float64)), name="x")
  879. exp = tm.box_expected(exp, box)
  880. tm.assert_equal(result, exp)
  881. result = np.divide(idx, 2.0)
  882. assert result.dtype == "f8" and isinstance(result, box)
  883. exp = Index([0.5, 1.0, 1.5, 2.0, 2.5], dtype=np.float64, name="x")
  884. exp = tm.box_expected(exp, box)
  885. tm.assert_equal(result, exp)
  886. # _evaluate_numeric_binop
  887. result = idx + 2.0
  888. assert result.dtype == "f8" and isinstance(result, box)
  889. exp = Index([3.0, 4.0, 5.0, 6.0, 7.0], dtype=np.float64, name="x")
  890. exp = tm.box_expected(exp, box)
  891. tm.assert_equal(result, exp)
  892. result = idx - 2.0
  893. assert result.dtype == "f8" and isinstance(result, box)
  894. exp = Index([-1.0, 0.0, 1.0, 2.0, 3.0], dtype=np.float64, name="x")
  895. exp = tm.box_expected(exp, box)
  896. tm.assert_equal(result, exp)
  897. result = idx * 1.0
  898. assert result.dtype == "f8" and isinstance(result, box)
  899. exp = Index([1.0, 2.0, 3.0, 4.0, 5.0], dtype=np.float64, name="x")
  900. exp = tm.box_expected(exp, box)
  901. tm.assert_equal(result, exp)
  902. result = idx / 2.0
  903. assert result.dtype == "f8" and isinstance(result, box)
  904. exp = Index([0.5, 1.0, 1.5, 2.0, 2.5], dtype=np.float64, name="x")
  905. exp = tm.box_expected(exp, box)
  906. tm.assert_equal(result, exp)
  907. # TODO: add more dtypes
  908. @pytest.mark.parametrize("holder", [Index, Series])
  909. @pytest.mark.parametrize("dtype", [np.int64, np.uint64, np.float64])
  910. def test_ufunc_multiple_return_values(self, holder, dtype):
  911. obj = holder([1, 2, 3], dtype=dtype, name="x")
  912. box = Series if holder is Series else Index
  913. result = np.modf(obj)
  914. assert isinstance(result, tuple)
  915. exp1 = Index([0.0, 0.0, 0.0], dtype=np.float64, name="x")
  916. exp2 = Index([1.0, 2.0, 3.0], dtype=np.float64, name="x")
  917. tm.assert_equal(result[0], tm.box_expected(exp1, box))
  918. tm.assert_equal(result[1], tm.box_expected(exp2, box))
  919. def test_ufunc_at(self):
  920. s = Series([0, 1, 2], index=[1, 2, 3], name="x")
  921. np.add.at(s, [0, 2], 10)
  922. expected = Series([10, 1, 12], index=[1, 2, 3], name="x")
  923. tm.assert_series_equal(s, expected)
  924. class TestObjectDtypeEquivalence:
  925. # Tests that arithmetic operations match operations executed elementwise
  926. @pytest.mark.parametrize("dtype", [None, object])
  927. def test_numarr_with_dtype_add_nan(self, dtype, box_with_array):
  928. box = box_with_array
  929. ser = Series([1, 2, 3], dtype=dtype)
  930. expected = Series([np.nan, np.nan, np.nan], dtype=dtype)
  931. ser = tm.box_expected(ser, box)
  932. expected = tm.box_expected(expected, box)
  933. result = np.nan + ser
  934. tm.assert_equal(result, expected)
  935. result = ser + np.nan
  936. tm.assert_equal(result, expected)
  937. @pytest.mark.parametrize("dtype", [None, object])
  938. def test_numarr_with_dtype_add_int(self, dtype, box_with_array):
  939. box = box_with_array
  940. ser = Series([1, 2, 3], dtype=dtype)
  941. expected = Series([2, 3, 4], dtype=dtype)
  942. ser = tm.box_expected(ser, box)
  943. expected = tm.box_expected(expected, box)
  944. result = 1 + ser
  945. tm.assert_equal(result, expected)
  946. result = ser + 1
  947. tm.assert_equal(result, expected)
  948. # TODO: moved from tests.series.test_operators; needs cleanup
  949. @pytest.mark.parametrize(
  950. "op",
  951. [operator.add, operator.sub, operator.mul, operator.truediv, operator.floordiv],
  952. )
  953. def test_operators_reverse_object(self, op):
  954. # GH#56
  955. arr = Series(np.random.randn(10), index=np.arange(10), dtype=object)
  956. result = op(1.0, arr)
  957. expected = op(1.0, arr.astype(float))
  958. tm.assert_series_equal(result.astype(float), expected)
  959. class TestNumericArithmeticUnsorted:
  960. # Tests in this class have been moved from type-specific test modules
  961. # but not yet sorted, parametrized, and de-duplicated
  962. @pytest.mark.parametrize(
  963. "op",
  964. [
  965. operator.add,
  966. operator.sub,
  967. operator.mul,
  968. operator.floordiv,
  969. operator.truediv,
  970. ],
  971. )
  972. @pytest.mark.parametrize(
  973. "idx1",
  974. [
  975. RangeIndex(0, 10, 1),
  976. RangeIndex(0, 20, 2),
  977. RangeIndex(-10, 10, 2),
  978. RangeIndex(5, -5, -1),
  979. ],
  980. )
  981. @pytest.mark.parametrize(
  982. "idx2",
  983. [
  984. RangeIndex(0, 10, 1),
  985. RangeIndex(0, 20, 2),
  986. RangeIndex(-10, 10, 2),
  987. RangeIndex(5, -5, -1),
  988. ],
  989. )
  990. def test_binops_index(self, op, idx1, idx2):
  991. idx1 = idx1._rename("foo")
  992. idx2 = idx2._rename("bar")
  993. result = op(idx1, idx2)
  994. expected = op(Index(idx1.to_numpy()), Index(idx2.to_numpy()))
  995. tm.assert_index_equal(result, expected, exact="equiv")
  996. @pytest.mark.parametrize(
  997. "op",
  998. [
  999. operator.add,
  1000. operator.sub,
  1001. operator.mul,
  1002. operator.floordiv,
  1003. operator.truediv,
  1004. ],
  1005. )
  1006. @pytest.mark.parametrize(
  1007. "idx",
  1008. [
  1009. RangeIndex(0, 10, 1),
  1010. RangeIndex(0, 20, 2),
  1011. RangeIndex(-10, 10, 2),
  1012. RangeIndex(5, -5, -1),
  1013. ],
  1014. )
  1015. @pytest.mark.parametrize("scalar", [-1, 1, 2])
  1016. def test_binops_index_scalar(self, op, idx, scalar):
  1017. result = op(idx, scalar)
  1018. expected = op(Index(idx.to_numpy()), scalar)
  1019. tm.assert_index_equal(result, expected, exact="equiv")
  1020. @pytest.mark.parametrize("idx1", [RangeIndex(0, 10, 1), RangeIndex(0, 20, 2)])
  1021. @pytest.mark.parametrize("idx2", [RangeIndex(0, 10, 1), RangeIndex(0, 20, 2)])
  1022. def test_binops_index_pow(self, idx1, idx2):
  1023. # numpy does not allow powers of negative integers so test separately
  1024. # https://github.com/numpy/numpy/pull/8127
  1025. idx1 = idx1._rename("foo")
  1026. idx2 = idx2._rename("bar")
  1027. result = pow(idx1, idx2)
  1028. expected = pow(Index(idx1.to_numpy()), Index(idx2.to_numpy()))
  1029. tm.assert_index_equal(result, expected, exact="equiv")
  1030. @pytest.mark.parametrize("idx", [RangeIndex(0, 10, 1), RangeIndex(0, 20, 2)])
  1031. @pytest.mark.parametrize("scalar", [1, 2])
  1032. def test_binops_index_scalar_pow(self, idx, scalar):
  1033. # numpy does not allow powers of negative integers so test separately
  1034. # https://github.com/numpy/numpy/pull/8127
  1035. result = pow(idx, scalar)
  1036. expected = pow(Index(idx.to_numpy()), scalar)
  1037. tm.assert_index_equal(result, expected, exact="equiv")
  1038. # TODO: divmod?
  1039. @pytest.mark.parametrize(
  1040. "op",
  1041. [
  1042. operator.add,
  1043. operator.sub,
  1044. operator.mul,
  1045. operator.floordiv,
  1046. operator.truediv,
  1047. operator.pow,
  1048. operator.mod,
  1049. ],
  1050. )
  1051. def test_arithmetic_with_frame_or_series(self, op):
  1052. # check that we return NotImplemented when operating with Series
  1053. # or DataFrame
  1054. index = RangeIndex(5)
  1055. other = Series(np.random.randn(5))
  1056. expected = op(Series(index), other)
  1057. result = op(index, other)
  1058. tm.assert_series_equal(result, expected)
  1059. other = pd.DataFrame(np.random.randn(2, 5))
  1060. expected = op(pd.DataFrame([index, index]), other)
  1061. result = op(index, other)
  1062. tm.assert_frame_equal(result, expected)
  1063. def test_numeric_compat2(self):
  1064. # validate that we are handling the RangeIndex overrides to numeric ops
  1065. # and returning RangeIndex where possible
  1066. idx = RangeIndex(0, 10, 2)
  1067. result = idx * 2
  1068. expected = RangeIndex(0, 20, 4)
  1069. tm.assert_index_equal(result, expected, exact=True)
  1070. result = idx + 2
  1071. expected = RangeIndex(2, 12, 2)
  1072. tm.assert_index_equal(result, expected, exact=True)
  1073. result = idx - 2
  1074. expected = RangeIndex(-2, 8, 2)
  1075. tm.assert_index_equal(result, expected, exact=True)
  1076. result = idx / 2
  1077. expected = RangeIndex(0, 5, 1).astype("float64")
  1078. tm.assert_index_equal(result, expected, exact=True)
  1079. result = idx / 4
  1080. expected = RangeIndex(0, 10, 2) / 4
  1081. tm.assert_index_equal(result, expected, exact=True)
  1082. result = idx // 1
  1083. expected = idx
  1084. tm.assert_index_equal(result, expected, exact=True)
  1085. # __mul__
  1086. result = idx * idx
  1087. expected = Index(idx.values * idx.values)
  1088. tm.assert_index_equal(result, expected, exact=True)
  1089. # __pow__
  1090. idx = RangeIndex(0, 1000, 2)
  1091. result = idx**2
  1092. expected = Index(idx._values) ** 2
  1093. tm.assert_index_equal(Index(result.values), expected, exact=True)
  1094. @pytest.mark.parametrize(
  1095. "idx, div, expected",
  1096. [
  1097. # TODO: add more dtypes
  1098. (RangeIndex(0, 1000, 2), 2, RangeIndex(0, 500, 1)),
  1099. (RangeIndex(-99, -201, -3), -3, RangeIndex(33, 67, 1)),
  1100. (
  1101. RangeIndex(0, 1000, 1),
  1102. 2,
  1103. Index(RangeIndex(0, 1000, 1)._values) // 2,
  1104. ),
  1105. (
  1106. RangeIndex(0, 100, 1),
  1107. 2.0,
  1108. Index(RangeIndex(0, 100, 1)._values) // 2.0,
  1109. ),
  1110. (RangeIndex(0), 50, RangeIndex(0)),
  1111. (RangeIndex(2, 4, 2), 3, RangeIndex(0, 1, 1)),
  1112. (RangeIndex(-5, -10, -6), 4, RangeIndex(-2, -1, 1)),
  1113. (RangeIndex(-100, -200, 3), 2, RangeIndex(0)),
  1114. ],
  1115. )
  1116. def test_numeric_compat2_floordiv(self, idx, div, expected):
  1117. # __floordiv__
  1118. tm.assert_index_equal(idx // div, expected, exact=True)
  1119. @pytest.mark.parametrize("dtype", [np.int64, np.float64])
  1120. @pytest.mark.parametrize("delta", [1, 0, -1])
  1121. def test_addsub_arithmetic(self, dtype, delta):
  1122. # GH#8142
  1123. delta = dtype(delta)
  1124. index = Index([10, 11, 12], dtype=dtype)
  1125. result = index + delta
  1126. expected = Index(index.values + delta, dtype=dtype)
  1127. tm.assert_index_equal(result, expected)
  1128. # this subtraction used to fail
  1129. result = index - delta
  1130. expected = Index(index.values - delta, dtype=dtype)
  1131. tm.assert_index_equal(result, expected)
  1132. tm.assert_index_equal(index + index, 2 * index)
  1133. tm.assert_index_equal(index - index, 0 * index)
  1134. assert not (index - index).empty
  1135. def test_fill_value_inf_masking():
  1136. # GH #27464 make sure we mask 0/1 with Inf and not NaN
  1137. df = pd.DataFrame({"A": [0, 1, 2], "B": [1.1, None, 1.1]})
  1138. other = pd.DataFrame({"A": [1.1, 1.2, 1.3]}, index=[0, 2, 3])
  1139. result = df.rfloordiv(other, fill_value=1)
  1140. expected = pd.DataFrame(
  1141. {"A": [np.inf, 1.0, 0.0, 1.0], "B": [0.0, np.nan, 0.0, np.nan]}
  1142. )
  1143. tm.assert_frame_equal(result, expected)
  1144. def test_dataframe_div_silenced():
  1145. # GH#26793
  1146. pdf1 = pd.DataFrame(
  1147. {
  1148. "A": np.arange(10),
  1149. "B": [np.nan, 1, 2, 3, 4] * 2,
  1150. "C": [np.nan] * 10,
  1151. "D": np.arange(10),
  1152. },
  1153. index=list("abcdefghij"),
  1154. columns=list("ABCD"),
  1155. )
  1156. pdf2 = pd.DataFrame(
  1157. np.random.randn(10, 4), index=list("abcdefghjk"), columns=list("ABCX")
  1158. )
  1159. with tm.assert_produces_warning(None):
  1160. pdf1.div(pdf2, fill_value=0)
  1161. @pytest.mark.parametrize(
  1162. "data, expected_data",
  1163. [([0, 1, 2], [0, 2, 4])],
  1164. )
  1165. def test_integer_array_add_list_like(
  1166. box_pandas_1d_array, box_1d_array, data, expected_data
  1167. ):
  1168. # GH22606 Verify operators with IntegerArray and list-likes
  1169. arr = array(data, dtype="Int64")
  1170. container = box_pandas_1d_array(arr)
  1171. left = container + box_1d_array(data)
  1172. right = box_1d_array(data) + container
  1173. if Series in [box_1d_array, box_pandas_1d_array]:
  1174. cls = Series
  1175. elif Index in [box_1d_array, box_pandas_1d_array]:
  1176. cls = Index
  1177. else:
  1178. cls = array
  1179. expected = cls(expected_data, dtype="Int64")
  1180. tm.assert_equal(left, expected)
  1181. tm.assert_equal(right, expected)
  1182. def test_sub_multiindex_swapped_levels():
  1183. # GH 9952
  1184. df = pd.DataFrame(
  1185. {"a": np.random.randn(6)},
  1186. index=pd.MultiIndex.from_product(
  1187. [["a", "b"], [0, 1, 2]], names=["levA", "levB"]
  1188. ),
  1189. )
  1190. df2 = df.copy()
  1191. df2.index = df2.index.swaplevel(0, 1)
  1192. result = df - df2
  1193. expected = pd.DataFrame([0.0] * 6, columns=["a"], index=df.index)
  1194. tm.assert_frame_equal(result, expected)
  1195. @pytest.mark.parametrize("power", [1, 2, 5])
  1196. @pytest.mark.parametrize("string_size", [0, 1, 2, 5])
  1197. def test_empty_str_comparison(power, string_size):
  1198. # GH 37348
  1199. a = np.array(range(10**power))
  1200. right = pd.DataFrame(a, dtype=np.int64)
  1201. left = " " * string_size
  1202. result = right == left
  1203. expected = pd.DataFrame(np.zeros(right.shape, dtype=bool))
  1204. tm.assert_frame_equal(result, expected)
  1205. def test_series_add_sub_with_UInt64():
  1206. # GH 22023
  1207. series1 = Series([1, 2, 3])
  1208. series2 = Series([2, 1, 3], dtype="UInt64")
  1209. result = series1 + series2
  1210. expected = Series([3, 3, 6], dtype="Float64")
  1211. tm.assert_series_equal(result, expected)
  1212. result = series1 - series2
  1213. expected = Series([-1, 1, 0], dtype="Float64")
  1214. tm.assert_series_equal(result, expected)