Skip to content

REF: _setitem_with_indexer_split_path #37521

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 31, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 71 additions & 71 deletions pandas/core/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1625,94 +1625,94 @@ def _setitem_with_indexer(self, indexer, value):
self._setitem_with_indexer_missing(indexer, value)
return

# set
item_labels = self.obj._get_axis(info_axis)

# align and set the values
if take_split_path:
# We have to operate column-wise
self._setitem_with_indexer_split_path(indexer, value)
else:
self._setitem_single_block(indexer, value)

# Above we only set take_split_path to True for 2D cases
assert self.ndim == 2
assert info_axis == 1
def _setitem_with_indexer_split_path(self, indexer, value):
"""
Setitem column-wise.
"""
# Above we only set take_split_path to True for 2D cases
assert self.ndim == 2

if not isinstance(indexer, tuple):
indexer = _tuplify(self.ndim, indexer)
if not isinstance(indexer, tuple):
indexer = _tuplify(self.ndim, indexer)

if isinstance(value, ABCSeries):
value = self._align_series(indexer, value)
if isinstance(value, ABCSeries):
value = self._align_series(indexer, value)

info_idx = indexer[info_axis]
if is_integer(info_idx):
info_idx = [info_idx]
labels = item_labels[info_idx]
info_idx = indexer[1]
if is_integer(info_idx):
info_idx = [info_idx]
labels = self.obj.columns[info_idx]

# Ensure we have something we can iterate over
ilocs = self._ensure_iterable_column_indexer(indexer[1])
# Ensure we have something we can iterate over
ilocs = self._ensure_iterable_column_indexer(indexer[1])

plane_indexer = indexer[:1]
lplane_indexer = length_of_indexer(plane_indexer[0], self.obj.index)
# lplane_indexer gives the expected length of obj[indexer[0]]
plane_indexer = indexer[:1]
lplane_indexer = length_of_indexer(plane_indexer[0], self.obj.index)
# lplane_indexer gives the expected length of obj[indexer[0]]

if len(labels) == 1:
# We can operate on a single column
if len(labels) == 1:
# We can operate on a single column

# require that we are setting the right number of values that
# we are indexing
if is_list_like_indexer(value) and 0 != lplane_indexer != len(value):
# Exclude zero-len for e.g. boolean masking that is all-false
raise ValueError(
"cannot set using a multi-index "
"selection indexer with a different "
"length than the value"
)

# we need an iterable, with a ndim of at least 1
# eg. don't pass through np.array(0)
if is_list_like_indexer(value) and getattr(value, "ndim", 1) > 0:

# we have an equal len Frame
if isinstance(value, ABCDataFrame):
self._setitem_with_indexer_frame_value(indexer, value)

# we have an equal len ndarray/convertible to our labels
# hasattr first, to avoid coercing to ndarray without reason.
# But we may be relying on the ndarray coercion to check ndim.
# Why not just convert to an ndarray earlier on if needed?
elif np.ndim(value) == 2:
self._setitem_with_indexer_2d_value(indexer, value)

elif (
len(labels) == 1
and lplane_indexer == len(value)
and not is_scalar(plane_indexer[0])
):
# we have an equal len list/ndarray
# We only get here with len(labels) == len(ilocs) == 1
self._setitem_single_column(ilocs[0], value, plane_indexer)
# require that we are setting the right number of values that
# we are indexing
if is_list_like_indexer(value) and 0 != lplane_indexer != len(value):
# Exclude zero-len for e.g. boolean masking that is all-false
raise ValueError(
"cannot set using a multi-index "
"selection indexer with a different "
"length than the value"
)

elif lplane_indexer == 0 and len(value) == len(self.obj.index):
# We get here in one case via .loc with a all-False mask
pass
# we need an iterable, with a ndim of at least 1
# eg. don't pass through np.array(0)
if is_list_like_indexer(value) and getattr(value, "ndim", 1) > 0:

# we have an equal len Frame
if isinstance(value, ABCDataFrame):
self._setitem_with_indexer_frame_value(indexer, value)

# we have an equal len ndarray/convertible to our labels
# hasattr first, to avoid coercing to ndarray without reason.
# But we may be relying on the ndarray coercion to check ndim.
# Why not just convert to an ndarray earlier on if needed?
elif np.ndim(value) == 2:
self._setitem_with_indexer_2d_value(indexer, value)

elif (
len(labels) == 1
and lplane_indexer == len(value)
and not is_scalar(plane_indexer[0])
):
# we have an equal len list/ndarray
# We only get here with len(labels) == len(ilocs) == 1
self._setitem_single_column(ilocs[0], value, plane_indexer)

else:
# per-label values
if len(ilocs) != len(value):
raise ValueError(
"Must have equal len keys and value "
"when setting with an iterable"
)
elif lplane_indexer == 0 and len(value) == len(self.obj.index):
# We get here in one case via .loc with a all-False mask
pass

for loc, v in zip(ilocs, value):
self._setitem_single_column(loc, v, plane_indexer)
else:
# per-label values
if len(ilocs) != len(value):
raise ValueError(
"Must have equal len keys and value "
"when setting with an iterable"
)

# scalar value
for loc in ilocs:
self._setitem_single_column(loc, value, plane_indexer)

for loc, v in zip(ilocs, value):
self._setitem_single_column(loc, v, plane_indexer)
else:
self._setitem_single_block(indexer, value)

# scalar value
for loc in ilocs:
self._setitem_single_column(loc, value, plane_indexer)

def _setitem_with_indexer_2d_value(self, indexer, value):
# We get here with np.ndim(value) == 2, excluding DataFrame,
Expand Down