diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 73892da2cbf71..37fed6e5e3bd3 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -730,6 +730,7 @@ Indexing - Bug in :meth:`Series.__getitem__` allowing missing labels with ``np.ndarray``, :class:`Index`, :class:`Series` indexers but not ``list``, these now all raise ``KeyError`` (:issue:`33646`) - Bug in :meth:`DataFrame.truncate` and :meth:`Series.truncate` where index was assumed to be monotone increasing (:issue:`33756`) - Indexing with a list of strings representing datetimes failed on :class:`DatetimeIndex` or :class:`PeriodIndex`(:issue:`11278`) +- Bug in :meth:`DataFrame.iloc` when setting values with list arguments would align row/column labels (:issue:`22046`) Missing ^^^^^^^ diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index b857a59195695..5cd9c8db1a1b2 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -662,6 +662,10 @@ def __setitem__(self, key, value): indexer = self._get_setitem_indexer(key) self._has_valid_setitem_indexer(key) + if self.name == "iloc" and isinstance(value, (ABCSeries, ABCDataFrame)): + # Strip labels so as to not align with RHS + value = value._values.copy() + iloc = self if self.name == "iloc" else self.obj.iloc iloc._setitem_with_indexer(indexer, value) @@ -1717,7 +1721,8 @@ def isetter(loc, v): for i, loc in enumerate(ilocs): # setting with a list, re-coerces - isetter(loc, value[:, i].tolist()) + # isetter(loc, value[:, i].tolist()) + isetter(loc, list(value[:, i])) elif ( len(labels) == 1 diff --git a/pandas/tests/indexing/test_iloc.py b/pandas/tests/indexing/test_iloc.py index c97cd81c84726..b9a4d3d10bff3 100644 --- a/pandas/tests/indexing/test_iloc.py +++ b/pandas/tests/indexing/test_iloc.py @@ -705,6 +705,15 @@ def test_iloc_setitem_categorical_updates_inplace(self): expected = pd.Categorical(["C", "B", "A"]) tm.assert_categorical_equal(cat, expected) + def test_iloc_setitem_frame_no_alignment(self): + # GH 22046 + # setting with iloc should not align labels + df = pd.DataFrame({"a": [1, 2], "b": [2, 3]}, index=[2, 1]) + expected = df.copy() + df2 = pd.DataFrame({"b": [1, 2], "a": [2, 3]}, index=[1, 2]) + df.iloc[:, [0, 1]] = df2.iloc[:, [0, 1]] + tm.assert_frame_equal(df, expected) + class TestILocSetItemDuplicateColumns: def test_iloc_setitem_scalar_duplicate_columns(self): @@ -733,3 +742,10 @@ def test_iloc_setitem_series_duplicate_columns(self): ) df.iloc[:, 0] = df.iloc[:, 0].astype(np.float64) assert df.dtypes.iloc[2] == np.int64 + + def test_iloc_settime_frame_duplicate_columns(self): + idx = pd.MultiIndex.from_tuples((("a", "a"), ("a", "a"))) + df = pd.DataFrame([[1, 1]], columns=idx) + expected = pd.DataFrame([[2, 2]], columns=idx) + df.iloc[:, [0, 1]] = expected.iloc[:, [0, 1]] + tm.assert_frame_equal(df, expected) diff --git a/pandas/tests/indexing/test_indexing.py b/pandas/tests/indexing/test_indexing.py index 51a7aa9bb586b..917741ef296f6 100644 --- a/pandas/tests/indexing/test_indexing.py +++ b/pandas/tests/indexing/test_indexing.py @@ -620,6 +620,20 @@ def test_astype_assignment(self): expected = DataFrame({"A": [1, 2, 3, 4]}) tm.assert_frame_equal(df, expected) + def test_astype_assignment_nolabel(self): + + # GH4312 (iloc) + df_orig = DataFrame( + [["1", "2", "3", ".4", 5, 6.0, "foo"]], columns=list("ABCDEFG") + ) + + df = df_orig.copy() + df.iloc[:, 0:2] = df.iloc[:, 0:2].values.astype(np.int64) + expected = DataFrame( + [[1, 2, "3", ".4", 5, 6.0, "foo"]], columns=list("ABCDEFG") + ) + tm.assert_frame_equal(df, expected) + def test_index_type_coercion(self): # GH 11836 @@ -716,27 +730,19 @@ def test_rhs_alignment(self): # GH8258, tests that both rows & columns are aligned to what is # assigned to. covers both uniform data-type & multi-type cases def run_tests(df, rhs, right): - # label, index, slice - lbl_one, idx_one, slice_one = list("bcd"), [1, 2, 3], slice(1, 4) - lbl_two, idx_two, slice_two = ["joe", "jolie"], [1, 2], slice(1, 3) + # labels + lbl_one = list("bcd") + lbl_two = ["joe", "jolie"] left = df.copy() left.loc[lbl_one, lbl_two] = rhs tm.assert_frame_equal(left, right) - left = df.copy() - left.iloc[idx_one, idx_two] = rhs - tm.assert_frame_equal(left, right) - - left = df.copy() - left.iloc[slice_one, slice_two] = rhs - tm.assert_frame_equal(left, right) - xs = np.arange(20).reshape(5, 4) cols = ["jim", "joe", "jolie", "joline"] df = DataFrame(xs, columns=cols, index=list("abcde")) - # right hand side; permute the indices and multiplpy by -2 + # right hand side; permute the indices and multiply by -2 rhs = -2 * df.iloc[3:0:-1, 2:0:-1] # expected `right` result; just multiply by -2