diff --git a/doc/source/release.rst b/doc/source/release.rst index f5e7e66c98a64..65e6ca0e1d95c 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -520,6 +520,7 @@ Bug Fixes chunks of the same file. Now coerces to numerical type or raises warning. (:issue:`3866`) - Fix a bug where reshaping a ``Series`` to its own shape raised ``TypeError`` (:issue:`4554`) and other reshaping issues. + - Bug in setting with ``ix/loc`` and a mixed int/string index (:issue:`4544`) pandas 0.12.0 ------------- diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index eb377c4b7955f..0d19736ed8083 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -783,9 +783,25 @@ def _convert_to_indexer(self, obj, axis=0, is_setter=False): - No, prefer label-based indexing """ labels = self.obj._get_axis(axis) + + # if we are a scalar indexer and not type correct raise + obj = self._convert_scalar_indexer(obj, axis) + + # see if we are positional in nature is_int_index = labels.is_integer() + is_int_positional = com.is_integer(obj) and not is_int_index - if com.is_integer(obj) and not is_int_index: + # if we are a label return me + try: + return labels.get_loc(obj) + except (KeyError, TypeError): + pass + except (ValueError): + if not is_int_positional: + raise + + # a positional + if is_int_positional: # if we are setting and its not a valid location # its an insert which fails by definition @@ -795,11 +811,6 @@ def _convert_to_indexer(self, obj, axis=0, is_setter=False): return obj - try: - return labels.get_loc(obj) - except (KeyError, TypeError): - pass - if isinstance(obj, slice): return self._convert_slice_indexer(obj, axis) diff --git a/pandas/tests/test_indexing.py b/pandas/tests/test_indexing.py index 837acb90407ea..67c87277647c8 100644 --- a/pandas/tests/test_indexing.py +++ b/pandas/tests/test_indexing.py @@ -1070,6 +1070,26 @@ def test_ix_assign_column_mixed(self): df['b'].ix[[1,3]] = [100,-100] assert_frame_equal(df,expected) + def test_ix_get_set_consistency(self): + + # GH 4544 + # ix/loc get/set not consistent when + # a mixed int/string index + df = DataFrame(np.arange(16).reshape((4, 4)), + columns=['a', 'b', 8, 'c'], + index=['e', 7, 'f', 'g']) + + self.assert_(df.ix['e', 8] == 2) + self.assert_(df.loc['e', 8] == 2) + + df.ix['e', 8] = 42 + self.assert_(df.ix['e', 8] == 42) + self.assert_(df.loc['e', 8] == 42) + + df.loc['e', 8] = 45 + self.assert_(df.ix['e', 8] == 45) + self.assert_(df.loc['e', 8] == 45) + def test_iloc_mask(self): # GH 3631, iloc with a mask (of a series) should raise diff --git a/pandas/tests/test_series.py b/pandas/tests/test_series.py index 1f0f7a5564142..a70f2931e36fe 100644 --- a/pandas/tests/test_series.py +++ b/pandas/tests/test_series.py @@ -878,7 +878,7 @@ def test_setitem_float_labels(self): tmp = s.copy() s.ix[1] = 'zoo' - tmp.values[1] = 'zoo' + tmp.iloc[2] = 'zoo' assert_series_equal(s, tmp)