Skip to content

BUG: iloc on DataFrame with reference is a silent no-op with unsorted indexes#65864

Open
rhshadrach wants to merge 2 commits into
pandas-dev:mainfrom
rhshadrach:bug_iloc_cow_noop
Open

BUG: iloc on DataFrame with reference is a silent no-op with unsorted indexes#65864
rhshadrach wants to merge 2 commits into
pandas-dev:mainfrom
rhshadrach:bug_iloc_cow_noop

Conversation

@rhshadrach

Copy link
Copy Markdown
Member

This appears to me to be a somewhat severe bug - using iloc has no impact when there is another reference to the DataFrame.

df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
ref = df[['A', 'B']]  # Create a reference
df.iloc[:, [1, 0]] = np.array([[10, 30], [20, 40]])
print(df)
#    A  B
# 0  1  3
# 1  2  4

The only thing that makes it not so severe is that the indices have to be not strictly increasing. I believe this was introduced in 2.1 with CoW enabled in #51435 but haven't run a git bisect here.

@rhshadrach rhshadrach added this to the 3.0.4 milestone Jun 12, 2026
@rhshadrach rhshadrach added Bug Indexing Related to indexing on series/frames, not to indexes themselves Regression Functionality that used to work in a prior pandas version Copy / view semantics labels Jun 12, 2026
col_indexer = 0
elif len(blk_loc) > 1:
elif len(inverse) > 1 and np.array_equal(
inverse, np.arange(len(blk_loc))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have a lib.is_range_indexer is something like that we can use here?

@jbrockmendel

Copy link
Copy Markdown
Member

claude found an existing bug that this changes to a different bug:

df = pd.DataFrame({"A": [1, 2], "B": [3, 4]})
ref = df[["A", "B"]]      # hold a reference -> CoW path
df.iloc[[1, 0], [1, 0]] = 99

on main the setitem is (incorrectly) a no-op. Under this PR, it sets the diagonal elements when it should set all the elements.

Fine if you want to consider out of scope.

# Block.delete in _iset_split_block requires sorted unique
# locs; inverse maps the requested column order onto the
# new block (GH#65446)
blk_loc, inverse = np.unique(blk_loc, return_inverse=True)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
blk_loc, inverse = np.unique(blk_loc, return_inverse=True)
blk_loc_unique, inverse = np.unique(blk_loc, return_inverse=True)

So we keep the original blk_loc? (eg I would assume the values = values[blk_locs] below needs to us the original blk_locs?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug Copy / view semantics Indexing Related to indexing on series/frames, not to indexes themselves Regression Functionality that used to work in a prior pandas version

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: Swapping values with iloc causes aligns axes, wrong example in docs

3 participants