From 325afdff78316b37f751a5d809d9b4df88318221 Mon Sep 17 00:00:00 2001 From: Wes McKinney Date: Mon, 17 Sep 2012 16:23:00 -0400 Subject: [PATCH] BUG: fix regression in negative integer indexing from 0.7.x close #1888 --- RELEASE.rst | 7 +++++++ pandas/core/indexing.py | 11 ++++++++++- pandas/tests/test_frame.py | 16 ++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/RELEASE.rst b/RELEASE.rst index 38e154aae4d52..b7876605c0372 100644 --- a/RELEASE.rst +++ b/RELEASE.rst @@ -48,6 +48,8 @@ pandas 0.9.0 - Add quoting option for DataFrame.to_csv (#1902) - Indicate long column value truncation in DataFrame output with ... (#1854) - DataFrame.dot will not do data alignment, and also work with Series (#1915) + - Add ``na`` option for missing data handling in some vectorized string + methods (#1689) **API Changes** @@ -169,6 +171,11 @@ pandas 0.9.0 - Raise Exception if set passed to Series constructor (#1913) - Add TypeError when appending HDFStore table w/ wrong index type (#1881) - Don't raise exception on empty inputs in EW functions (e.g. ewma) (#1900) + - Make asof work correctly with PeriodIndex (#1883) + - Fix extlinks in doc build + - Fill boolean DataFrame with NaN when calling shift (#1814) + - Fix setuptools bug causing pip not to Cythonize .pyx files sometimes + - Fix negative integer indexing regression in .ix from 0.7.x (#1888) pandas 0.8.1 ============ diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 661e13748cc0e..4bb11c3992129 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -293,7 +293,8 @@ def _reindex(keys, level=None): inds, = np.asarray(key, dtype=bool).nonzero() return self.obj.take(inds, axis=axis) else: - if isinstance(key, Index): + was_index = isinstance(key, Index) + if was_index: # want Index objects to pass through untouched keyarr = key else: @@ -301,6 +302,10 @@ def _reindex(keys, level=None): keyarr = _asarray_tuplesafe(key) if _is_integer_dtype(keyarr): + if labels.inferred_type != 'integer': + keyarr = np.where(keyarr < 0, + len(labels) + keyarr, keyarr) + if labels.inferred_type == 'mixed-integer': indexer = labels.get_indexer(keyarr) if (indexer >= 0).all(): @@ -308,6 +313,7 @@ def _reindex(keys, level=None): else: return self.obj.take(keyarr, axis=axis) elif not labels.inferred_type == 'integer': + return self.obj.take(keyarr, axis=axis) # this is not the most robust, but... @@ -406,6 +412,9 @@ def _convert_to_indexer(self, obj, axis=0): # If have integer labels, defer to label-based indexing if _is_integer_dtype(objarr) and not is_int_index: + if labels.inferred_type != 'integer': + objarr = np.where(objarr < 0, + len(labels) + objarr, objarr) return objarr # this is not the most robust, but... diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py index 1f01886fcb34e..2764eb670e0d4 100644 --- a/pandas/tests/test_frame.py +++ b/pandas/tests/test_frame.py @@ -175,6 +175,22 @@ def test_getitem_ix_mixed_integer(self): expected = df.ix[Index([1, 10], dtype=object)] assert_frame_equal(result, expected) + def test_getitem_setitem_ix_negative_integers(self): + result = self.frame.ix[:, -1] + assert_series_equal(result, self.frame['D']) + + result = self.frame.ix[:, [-1]] + assert_frame_equal(result, self.frame[['D']]) + + result = self.frame.ix[:, [-1, -2]] + assert_frame_equal(result, self.frame[['D', 'C']]) + + self.frame.ix[:, [-1]] = 0 + self.assert_((self.frame['D'] == 0).all()) + + df = DataFrame(np.random.randn(8, 4)) + self.assert_(isnull(df.ix[:, [-1]].values).all()) + def test_getattr(self): tm.assert_series_equal(self.frame.A, self.frame['A']) self.assertRaises(AttributeError, getattr, self.frame,