From 0c0c647bde50d9112f9ea0a4cc0e3556af5bb7c2 Mon Sep 17 00:00:00 2001 From: jreback Date: Tue, 18 Feb 2014 08:47:55 -0500 Subject: [PATCH] BUG: Regression in chained getitem indexing with embedded list-like from 0.12 (6394) --- doc/source/release.rst | 1 + pandas/core/generic.py | 6 +++++- pandas/core/series.py | 11 +++++++++-- pandas/tests/test_indexing.py | 20 ++++++++++++++++++++ pandas/tests/test_series.py | 7 +++++++ 5 files changed, 42 insertions(+), 3 deletions(-) diff --git a/doc/source/release.rst b/doc/source/release.rst index b58a990a98a1d..c244ac59cb1f7 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -135,6 +135,7 @@ Bug Fixes - Bug in Series.get, was using a buggy access method (:issue:`6383`) - Bug in hdfstore queries of the form ``where=[('date', '>=', datetime(2013,1,1)), ('date', '<=', datetime(2014,1,1))]`` (:issue:`6313`) - Bug in DataFrame.dropna with duplicate indices (:issue:`6355`) +- Regression in chained getitem indexing with embedded list-like from 0.12 (:issue:`6394`) pandas 0.13.1 ------------- diff --git a/pandas/core/generic.py b/pandas/core/generic.py index b9ffeb636615b..bf682f7c50252 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -1312,7 +1312,11 @@ def xs(self, key, axis=0, level=None, copy=True, drop_level=True): new_values, copy = self._data.fast_xs(loc, copy=copy) # may need to box a datelike-scalar - if not is_list_like(new_values): + # + # if we encounter an array-like and we only have 1 dim + # that means that their are list/ndarrays inside the Series! + # so just return them (GH 6394) + if not is_list_like(new_values) or self.ndim == 1: return _maybe_box_datetimelike(new_values) result = Series(new_values, index=self.columns, diff --git a/pandas/core/series.py b/pandas/core/series.py index 50b22ae8dd785..8a500409de97a 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -477,8 +477,15 @@ def _slice(self, slobj, axis=0, raise_on_error=False, typ=None): def __getitem__(self, key): try: result = self.index.get_value(self, key) - if isinstance(result, np.ndarray): - return self._constructor(result,index=[key]*len(result)).__finalize__(self) + + if not np.isscalar(result): + if is_list_like(result) and not isinstance(result, Series): + + # we need to box if we have a non-unique index here + # otherwise have inline ndarray/lists + if not self.index.is_unique: + result = self._constructor(result,index=[key]*len(result)).__finalize__(self) + return result except InvalidIndexError: pass diff --git a/pandas/tests/test_indexing.py b/pandas/tests/test_indexing.py index e16f3221af40c..54cf8046b90d0 100644 --- a/pandas/tests/test_indexing.py +++ b/pandas/tests/test_indexing.py @@ -551,6 +551,26 @@ def test_loc_setitem(self): expected = DataFrame({'a' : [0.5,-0.5,-1.5], 'b' : [0,1,2] }) assert_frame_equal(df,expected) + def test_chained_getitem_with_lists(self): + + # GH6394 + # Regression in chained getitem indexing with embedded list-like from 0.12 + def check(result, expected): + self.assert_numpy_array_equal(result,expected) + tm.assert_isinstance(result, np.ndarray) + + + df = DataFrame({'A': 5*[np.zeros(3)], 'B':5*[np.ones(3)]}) + expected = df['A'].iloc[2] + result = df.loc[2,'A'] + check(result, expected) + result2 = df.iloc[2]['A'] + check(result2, expected) + result3 = df['A'].loc[2] + check(result3, expected) + result4 = df['A'].iloc[2] + check(result4, expected) + def test_loc_getitem_int(self): # int label diff --git a/pandas/tests/test_series.py b/pandas/tests/test_series.py index 6e9e427f2e816..18f8a4b25abb5 100644 --- a/pandas/tests/test_series.py +++ b/pandas/tests/test_series.py @@ -949,6 +949,12 @@ def test_getitem_dups_with_missing(self): result = s[['foo', 'bar', 'bah', 'bam']] assert_series_equal(result, expected) + def test_getitem_dups(self): + s = Series(range(5),index=['A','A','B','C','C']) + expected = Series([3,4],index=['C','C']) + result = s['C'] + assert_series_equal(result, expected) + def test_setitem_ambiguous_keyerror(self): s = Series(lrange(10), index=lrange(0, 20, 2)) @@ -4813,6 +4819,7 @@ def test_apply_args(self): result = s.apply(str.split, args=(',',)) self.assertEqual(result[0], ['foo', 'bar']) + tm.assert_isinstance(result[0], list) def test_align(self): def _check_align(a, b, how='left', fill=None):