Skip to content

Commit 8e0b744

Browse files
authored
REF: Block.putmask dont use split_and_operate (#40281)
1 parent a476825 commit 8e0b744

File tree

2 files changed

+24
-39
lines changed

2 files changed

+24
-39
lines changed

pandas/core/array_algos/putmask.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def putmask_smart(values: np.ndarray, mask: np.ndarray, new) -> np.ndarray:
8181

8282
# n should be the length of the mask or a scalar here
8383
if not is_list_like(new):
84-
new = np.repeat(new, len(mask))
84+
new = np.broadcast_to(new, mask.shape)
8585

8686
# see if we are only masking values that if putted
8787
# will work in the current dtype

pandas/core/internals/blocks.py

Lines changed: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,64 +1058,49 @@ def putmask(self, mask, new) -> List[Block]:
10581058
-------
10591059
List[Block]
10601060
"""
1061-
transpose = self.ndim == 2
1061+
orig_mask = mask
10621062
mask, noop = validate_putmask(self.values.T, mask)
10631063
assert not isinstance(new, (ABCIndex, ABCSeries, ABCDataFrame))
10641064

1065-
new_values = self.values # delay copy if possible.
10661065
# if we are passed a scalar None, convert it here
1067-
if not is_list_like(new) and isna(new) and not self.is_object:
1068-
# FIXME: make sure we have compatible NA
1066+
if not self.is_object and is_valid_na_for_dtype(new, self.dtype):
10691067
new = self.fill_value
10701068

10711069
if self._can_hold_element(new):
1072-
if transpose:
1073-
new_values = new_values.T
10741070

1075-
putmask_without_repeat(new_values, mask, new)
1071+
putmask_without_repeat(self.values.T, mask, new)
10761072
return [self]
10771073

10781074
elif noop:
10791075
return [self]
10801076

10811077
dtype, _ = infer_dtype_from(new)
10821078
if dtype.kind in ["m", "M"]:
1083-
# using putmask with object dtype will incorrect cast to object
1079+
# using putmask with object dtype will incorrectly cast to object
10841080
# Having excluded self._can_hold_element, we know we cannot operate
10851081
# in-place, so we are safe using `where`
10861082
return self.where(new, ~mask)
10871083

1088-
else:
1089-
# may need to upcast
1090-
if transpose:
1091-
mask = mask.T
1092-
if isinstance(new, np.ndarray):
1093-
new = new.T
1094-
1095-
# operate column-by-column
1096-
def f(mask, val, idx):
1097-
1098-
if idx is None:
1099-
# ndim==1 case.
1100-
n = new
1101-
else:
1102-
1103-
if isinstance(new, np.ndarray):
1104-
n = np.squeeze(new[idx % new.shape[0]])
1105-
else:
1106-
n = np.array(new)
1107-
1108-
# type of the new block
1109-
dtype = find_common_type([n.dtype, val.dtype])
1110-
1111-
# we need to explicitly astype here to make a copy
1112-
n = n.astype(dtype)
1113-
1114-
nv = putmask_smart(val, mask, n)
1115-
return nv
1084+
elif self.ndim == 1 or self.shape[0] == 1:
1085+
# no need to split columns
1086+
nv = putmask_smart(self.values.T, mask, new).T
1087+
return [self.make_block(nv)]
11161088

1117-
new_blocks = self.split_and_operate(mask, f, True)
1118-
return new_blocks
1089+
else:
1090+
is_array = isinstance(new, np.ndarray)
1091+
1092+
res_blocks = []
1093+
nbs = self._split()
1094+
for i, nb in enumerate(nbs):
1095+
n = new
1096+
if is_array:
1097+
# we have a different value per-column
1098+
n = new[:, i : i + 1]
1099+
1100+
submask = orig_mask[:, i : i + 1]
1101+
rbs = nb.putmask(submask, n)
1102+
res_blocks.extend(rbs)
1103+
return res_blocks
11191104

11201105
@final
11211106
def coerce_to_target_dtype(self, other) -> Block:

0 commit comments

Comments
 (0)