|
76 | 76 | from pandas.core.array_algos.quantile import quantile_with_mask
|
77 | 77 | from pandas.core.arraylike import OpsMixin
|
78 | 78 | from pandas.core.arrays import ExtensionArray
|
| 79 | +from pandas.core.construction import ensure_wrapped_if_datetimelike |
79 | 80 | from pandas.core.indexers import check_array_indexer
|
80 | 81 | from pandas.core.ops import invalid_comparison
|
81 | 82 |
|
@@ -593,6 +594,85 @@ def _propagate_mask(
|
593 | 594 | mask = self._mask | mask
|
594 | 595 | return mask
|
595 | 596 |
|
| 597 | + def _arith_method(self, other, op): |
| 598 | + op_name = op.__name__ |
| 599 | + omask = None |
| 600 | + |
| 601 | + if isinstance(other, BaseMaskedArray): |
| 602 | + other, omask = other._data, other._mask |
| 603 | + |
| 604 | + elif is_list_like(other): |
| 605 | + if not isinstance(other, ExtensionArray): |
| 606 | + other = np.asarray(other) |
| 607 | + if other.ndim > 1: |
| 608 | + raise NotImplementedError("can only perform ops with 1-d structures") |
| 609 | + |
| 610 | + # We wrap the non-masked arithmetic logic used for numpy dtypes |
| 611 | + # in Series/Index arithmetic ops. |
| 612 | + other = ops.maybe_prepare_scalar_for_op(other, (len(self),)) |
| 613 | + pd_op = ops.get_array_op(op) |
| 614 | + other = ensure_wrapped_if_datetimelike(other) |
| 615 | + |
| 616 | + if op_name in {"pow", "rpow"} and isinstance(other, np.bool_): |
| 617 | + # Avoid DeprecationWarning: In future, it will be an error |
| 618 | + # for 'np.bool_' scalars to be interpreted as an index |
| 619 | + # e.g. test_array_scalar_like_equivalence |
| 620 | + other = bool(other) |
| 621 | + |
| 622 | + mask = self._propagate_mask(omask, other) |
| 623 | + |
| 624 | + if other is libmissing.NA: |
| 625 | + result = np.ones_like(self._data) |
| 626 | + if self.dtype.kind == "b": |
| 627 | + if op_name in {"floordiv", "rfloordiv", "mod", "rmod", "pow", "rpow"}: |
| 628 | + dtype = "int8" |
| 629 | + elif op_name in {"truediv", "rtruediv"}: |
| 630 | + dtype = "float64" |
| 631 | + else: |
| 632 | + dtype = "bool" |
| 633 | + result = result.astype(dtype) |
| 634 | + elif "truediv" in op_name and self.dtype.kind != "f": |
| 635 | + # The actual data here doesn't matter since the mask |
| 636 | + # will be all-True, but since this is division, we want |
| 637 | + # to end up with floating dtype. |
| 638 | + result = result.astype(np.float64) |
| 639 | + else: |
| 640 | + # Make sure we do this before the "pow" mask checks |
| 641 | + # to get an expected exception message on shape mismatch. |
| 642 | + if self.dtype.kind in ["i", "u"] and op_name in ["floordiv", "mod"]: |
| 643 | + # TODO(GH#30188) ATM we don't match the behavior of non-masked |
| 644 | + # types with respect to floordiv-by-zero |
| 645 | + pd_op = op |
| 646 | + |
| 647 | + elif self.dtype.kind == "b" and ( |
| 648 | + "div" in op_name or "pow" in op_name or "mod" in op_name |
| 649 | + ): |
| 650 | + # TODO(GH#41165): should these be disallowed? |
| 651 | + pd_op = op |
| 652 | + |
| 653 | + with np.errstate(all="ignore"): |
| 654 | + result = pd_op(self._data, other) |
| 655 | + |
| 656 | + if op_name == "pow": |
| 657 | + # 1 ** x is 1. |
| 658 | + mask = np.where((self._data == 1) & ~self._mask, False, mask) |
| 659 | + # x ** 0 is 1. |
| 660 | + if omask is not None: |
| 661 | + mask = np.where((other == 0) & ~omask, False, mask) |
| 662 | + elif other is not libmissing.NA: |
| 663 | + mask = np.where(other == 0, False, mask) |
| 664 | + |
| 665 | + elif op_name == "rpow": |
| 666 | + # 1 ** x is 1. |
| 667 | + if omask is not None: |
| 668 | + mask = np.where((other == 1) & ~omask, False, mask) |
| 669 | + elif other is not libmissing.NA: |
| 670 | + mask = np.where(other == 1, False, mask) |
| 671 | + # x ** 0 is 1. |
| 672 | + mask = np.where((self._data == 0) & ~self._mask, False, mask) |
| 673 | + |
| 674 | + return self._maybe_mask_result(result, mask, other, op_name) |
| 675 | + |
596 | 676 | def _cmp_method(self, other, op) -> BooleanArray:
|
597 | 677 | from pandas.core.arrays import BooleanArray
|
598 | 678 |
|
|
0 commit comments