|
1 | 1 | import inspect
|
2 | 2 | import re
|
3 | 3 | from typing import TYPE_CHECKING, Any, List, Optional, Type, Union, cast
|
4 |
| -import warnings |
5 | 4 |
|
6 | 5 | import numpy as np
|
7 | 6 |
|
|
42 | 41 | is_dtype_equal,
|
43 | 42 | is_extension_array_dtype,
|
44 | 43 | is_float,
|
45 |
| - is_float_dtype, |
46 | 44 | is_integer,
|
47 |
| - is_integer_dtype, |
48 | 45 | is_list_like,
|
49 | 46 | is_object_dtype,
|
50 | 47 | is_re,
|
|
54 | 51 | )
|
55 | 52 | from pandas.core.dtypes.dtypes import CategoricalDtype, ExtensionDtype
|
56 | 53 | from pandas.core.dtypes.generic import ABCDataFrame, ABCIndex, ABCPandasArray, ABCSeries
|
57 |
| -from pandas.core.dtypes.missing import is_valid_nat_for_dtype, isna, isna_compat |
| 54 | +from pandas.core.dtypes.missing import is_valid_nat_for_dtype, isna |
58 | 55 |
|
59 | 56 | import pandas.core.algorithms as algos
|
| 57 | +from pandas.core.array_algos.putmask import putmask_inplace, putmask_smart |
60 | 58 | from pandas.core.array_algos.replace import compare_or_regex_search, replace_regex
|
61 | 59 | from pandas.core.array_algos.transforms import shift
|
62 | 60 | from pandas.core.arrays import (
|
@@ -437,7 +435,7 @@ def fillna(
|
437 | 435 |
|
438 | 436 | if self._can_hold_element(value):
|
439 | 437 | nb = self if inplace else self.copy()
|
440 |
| - nb._putmask_simple(mask, value) |
| 438 | + putmask_inplace(nb.values, mask, value) |
441 | 439 | # TODO: should be nb._maybe_downcast?
|
442 | 440 | return self._maybe_downcast([nb], downcast)
|
443 | 441 |
|
@@ -762,7 +760,7 @@ def replace(
|
762 | 760 | )
|
763 | 761 |
|
764 | 762 | blk = self if inplace else self.copy()
|
765 |
| - blk._putmask_simple(mask, value) |
| 763 | + putmask_inplace(blk.values, mask, value) |
766 | 764 | blocks = blk.convert(numeric=False, copy=not inplace)
|
767 | 765 | return blocks
|
768 | 766 |
|
@@ -991,35 +989,6 @@ def setitem(self, indexer, value):
|
991 | 989 | block = self.make_block(values)
|
992 | 990 | return block
|
993 | 991 |
|
994 |
| - def _putmask_simple(self, mask: np.ndarray, value: Any): |
995 |
| - """ |
996 |
| - Like putmask but |
997 |
| -
|
998 |
| - a) we do not cast on failure |
999 |
| - b) we do not handle repeating or truncating like numpy. |
1000 |
| -
|
1001 |
| - Parameters |
1002 |
| - ---------- |
1003 |
| - mask : np.ndarray[bool] |
1004 |
| - We assume _extract_bool_array has already been called. |
1005 |
| - value : Any |
1006 |
| - We assume self._can_hold_element(value) |
1007 |
| - """ |
1008 |
| - values = self.values |
1009 |
| - |
1010 |
| - if lib.is_scalar(value) and isinstance(values, np.ndarray): |
1011 |
| - value = convert_scalar_for_putitemlike(value, values.dtype) |
1012 |
| - |
1013 |
| - if self.is_extension or (self.is_object and not lib.is_scalar(value)): |
1014 |
| - # GH#19266 using np.putmask gives unexpected results with listlike value |
1015 |
| - if is_list_like(value) and len(value) == len(values): |
1016 |
| - values[mask] = value[mask] |
1017 |
| - else: |
1018 |
| - values[mask] = value |
1019 |
| - else: |
1020 |
| - # GH#37833 np.putmask is more performant than __setitem__ |
1021 |
| - np.putmask(values, mask, value) |
1022 |
| - |
1023 | 992 | def putmask(self, mask, new, axis: int = 0) -> List["Block"]:
|
1024 | 993 | """
|
1025 | 994 | putmask the data to the block; it is possible that we may create a
|
@@ -1121,7 +1090,7 @@ def f(mask, val, idx):
|
1121 | 1090 | # we need to explicitly astype here to make a copy
|
1122 | 1091 | n = n.astype(dtype)
|
1123 | 1092 |
|
1124 |
| - nv = _putmask_smart(val, mask, n) |
| 1093 | + nv = putmask_smart(val, mask, n) |
1125 | 1094 | return nv
|
1126 | 1095 |
|
1127 | 1096 | new_blocks = self.split_and_operate(mask, f, True)
|
@@ -1560,7 +1529,7 @@ def _replace_coerce(
|
1560 | 1529 | nb = self.coerce_to_target_dtype(value)
|
1561 | 1530 | if nb is self and not inplace:
|
1562 | 1531 | nb = nb.copy()
|
1563 |
| - nb._putmask_simple(mask, value) |
| 1532 | + putmask_inplace(nb.values, mask, value) |
1564 | 1533 | return [nb]
|
1565 | 1534 | else:
|
1566 | 1535 | regex = _should_use_regex(regex, to_replace)
|
@@ -2665,86 +2634,6 @@ def safe_reshape(arr, new_shape: Shape):
|
2665 | 2634 | return arr
|
2666 | 2635 |
|
2667 | 2636 |
|
2668 |
| -def _putmask_smart(v: np.ndarray, mask: np.ndarray, n) -> np.ndarray: |
2669 |
| - """ |
2670 |
| - Return a new ndarray, try to preserve dtype if possible. |
2671 |
| -
|
2672 |
| - Parameters |
2673 |
| - ---------- |
2674 |
| - v : np.ndarray |
2675 |
| - `values`, updated in-place. |
2676 |
| - mask : np.ndarray[bool] |
2677 |
| - Applies to both sides (array like). |
2678 |
| - n : `new values` either scalar or an array like aligned with `values` |
2679 |
| -
|
2680 |
| - Returns |
2681 |
| - ------- |
2682 |
| - values : ndarray with updated values |
2683 |
| - this *may* be a copy of the original |
2684 |
| -
|
2685 |
| - See Also |
2686 |
| - -------- |
2687 |
| - ndarray.putmask |
2688 |
| - """ |
2689 |
| - # we cannot use np.asarray() here as we cannot have conversions |
2690 |
| - # that numpy does when numeric are mixed with strings |
2691 |
| - |
2692 |
| - # n should be the length of the mask or a scalar here |
2693 |
| - if not is_list_like(n): |
2694 |
| - n = np.repeat(n, len(mask)) |
2695 |
| - |
2696 |
| - # see if we are only masking values that if putted |
2697 |
| - # will work in the current dtype |
2698 |
| - try: |
2699 |
| - nn = n[mask] |
2700 |
| - except TypeError: |
2701 |
| - # TypeError: only integer scalar arrays can be converted to a scalar index |
2702 |
| - pass |
2703 |
| - else: |
2704 |
| - # make sure that we have a nullable type |
2705 |
| - # if we have nulls |
2706 |
| - if not isna_compat(v, nn[0]): |
2707 |
| - pass |
2708 |
| - elif not (is_float_dtype(nn.dtype) or is_integer_dtype(nn.dtype)): |
2709 |
| - # only compare integers/floats |
2710 |
| - pass |
2711 |
| - elif not (is_float_dtype(v.dtype) or is_integer_dtype(v.dtype)): |
2712 |
| - # only compare integers/floats |
2713 |
| - pass |
2714 |
| - else: |
2715 |
| - |
2716 |
| - # we ignore ComplexWarning here |
2717 |
| - with warnings.catch_warnings(record=True): |
2718 |
| - warnings.simplefilter("ignore", np.ComplexWarning) |
2719 |
| - nn_at = nn.astype(v.dtype) |
2720 |
| - |
2721 |
| - comp = nn == nn_at |
2722 |
| - if is_list_like(comp) and comp.all(): |
2723 |
| - nv = v.copy() |
2724 |
| - nv[mask] = nn_at |
2725 |
| - return nv |
2726 |
| - |
2727 |
| - n = np.asarray(n) |
2728 |
| - |
2729 |
| - def _putmask_preserve(nv, n): |
2730 |
| - try: |
2731 |
| - nv[mask] = n[mask] |
2732 |
| - except (IndexError, ValueError): |
2733 |
| - nv[mask] = n |
2734 |
| - return nv |
2735 |
| - |
2736 |
| - # preserves dtype if possible |
2737 |
| - if v.dtype.kind == n.dtype.kind: |
2738 |
| - return _putmask_preserve(v, n) |
2739 |
| - |
2740 |
| - # change the dtype if needed |
2741 |
| - dtype, _ = maybe_promote(n.dtype) |
2742 |
| - |
2743 |
| - v = v.astype(dtype) |
2744 |
| - |
2745 |
| - return _putmask_preserve(v, n) |
2746 |
| - |
2747 |
| - |
2748 | 2637 | def _extract_bool_array(mask: ArrayLike) -> np.ndarray:
|
2749 | 2638 | """
|
2750 | 2639 | If we have a SparseArray or BooleanArray, convert it to ndarray[bool].
|
|
0 commit comments