Skip to content

BUG: loc was failing on integer slices (incorrect implementation), GH 3053 #3055

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 14, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion RELEASE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pandas 0.11.0
- Add ``squeeze`` function to reduce dimensionality of 1-len objects
- Support slicing with time objects (GH2681_)
- Added ``.iloc`` attribute, to support strict integer based indexing, analagous to ``.ix`` (GH2922_)
- Added ``.loc`` attribute, to support strict label based indexing, analagous to ``.ix``
- Added ``.loc`` attribute, to support strict label based indexing, analagous to ``.ix`` (GH3053_)
- Added ``.iat`` attribute, to support fast scalar access via integers (replaces ``iget_value/iset_value``)
- Added ``.at`` attribute, to support fast scalar access via labels (replaces ``get_value/set_value``)
- Moved functionaility from ``irow,icol,iget_value/iset_value`` to ``.iloc`` indexer
Expand Down Expand Up @@ -183,6 +183,7 @@ pandas 0.11.0
.. _GH3012: https://github.com/pydata/pandas/issues/3012
.. _GH3029: https://github.com/pydata/pandas/issues/3029
.. _GH3041: https://github.com/pydata/pandas/issues/3041
.. _GH3053: https://github.com/pydata/pandas/issues/3053


pandas 0.10.1
Expand Down
23 changes: 15 additions & 8 deletions pandas/core/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,19 @@ def _getbool_axis(self, key, axis=0):
return self.obj.take(inds, axis=axis)
except (Exception), detail:
raise self._exception(detail)
def _get_slice_axis(self, slice_obj, axis=0):
""" this is pretty simple as we just have to deal with labels """
obj = self.obj
if not _need_slice(slice_obj):
return obj

labels = obj._get_axis(axis)
indexer = labels.slice_indexer(slice_obj.start, slice_obj.stop, slice_obj.step)

if isinstance(indexer, slice):
return self._slice(indexer, axis=axis)
else:
return self.obj.take(indexer, axis=axis)

class _LocIndexer(_LocationIndexer):
""" purely label based location based indexing """
Expand All @@ -667,11 +680,8 @@ def _has_valid_type(self, key, axis):
if key.start not in ax:
raise KeyError("start bound [%s] is not the [%s]" % (key.start,self.obj._get_axis_name(axis)))
if key.stop is not None:
stop = key.stop
if com.is_integer(stop):
stop -= 1
if stop not in ax:
raise KeyError("stop bound [%s] is not in the [%s]" % (stop,self.obj._get_axis_name(axis)))
if key.stop not in ax:
raise KeyError("stop bound [%s] is not in the [%s]" % (key.stop,self.obj._get_axis_name(axis)))

elif com._is_bool_indexer(key):
return True
Expand Down Expand Up @@ -700,9 +710,6 @@ def _getitem_axis(self, key, axis=0):
labels = self.obj._get_axis(axis)

if isinstance(key, slice):
ltype = labels.inferred_type
if ltype == 'mixed-integer-float' or ltype == 'mixed-integer':
raise ValueError('cannot slice with a non-single type label array')
return self._get_slice_axis(key, axis=axis)
elif com._is_bool_indexer(key):
return self._getbool_axis(key, axis=axis)
Expand Down
37 changes: 31 additions & 6 deletions pandas/tests/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,12 +450,38 @@ def test_loc_getitem_bool(self):
def test_loc_getitem_int_slice(self):

# int slices in int
self.check_result('int slice1', 'loc', slice(1,3), 'ix', { 0 : [2,4], 1: [3,6], 2: [4,8] }, typs = ['ints'], fails=KeyError)
self.check_result('int slice1', 'loc', slice(2,4), 'ix', { 0 : [2,4], 1: [3,6], 2: [4,8] }, typs = ['ints'], fails=KeyError)

# ok
self.check_result('int slice2', 'loc', slice(2,5), 'ix', [2,4], typs = ['ints'], axes = 0)
self.check_result('int slice2', 'loc', slice(3,7), 'ix', [3,6], typs = ['ints'], axes = 1)
self.check_result('int slice2', 'loc', slice(4,9), 'ix', [4,8], typs = ['ints'], axes = 2)
self.check_result('int slice2', 'loc', slice(2,4), 'ix', [2,4], typs = ['ints'], axes = 0)
self.check_result('int slice2', 'loc', slice(3,6), 'ix', [3,6], typs = ['ints'], axes = 1)
self.check_result('int slice2', 'loc', slice(4,8), 'ix', [4,8], typs = ['ints'], axes = 2)

# GH 3053
# loc should treat integer slices like label slices
from itertools import product

index = MultiIndex.from_tuples([t for t in product([6,7,8], ['a', 'b'])])
df = DataFrame(np.random.randn(6, 6), index, index)
result = df.loc[6:8,:]
expected = df.ix[6:8,:]
assert_frame_equal(result,expected)

index = MultiIndex.from_tuples([t for t in product([10, 20, 30], ['a', 'b'])])
df = DataFrame(np.random.randn(6, 6), index, index)
result = df.loc[20:30,:]
expected = df.ix[20:30,:]
assert_frame_equal(result,expected)

# doc examples
result = df.loc[10,:]
expected = df.ix[10,:]
assert_frame_equal(result,expected)

result = df.loc[:,10]
#expected = df.ix[:,10] (this fails)
expected = df[10]
assert_frame_equal(result,expected)

def test_loc_getitem_label_slice(self):

Expand All @@ -475,8 +501,7 @@ def test_loc_getitem_label_slice(self):
self.check_result('mixed slice', 'loc', slice(2,8), 'ix', slice(2,8), typs = ['mixed'], axes=1, fails=KeyError)
self.check_result('mixed slice', 'loc', slice(2,8), 'ix', slice(2,8), typs = ['mixed'], axes=2, fails=KeyError)

# you would think this would work, but we don't have an ordering, so fail
self.check_result('mixed slice', 'loc', slice(2,5,2), 'ix', slice(2,4,2), typs = ['mixed'], axes=0, fails=ValueError)
self.check_result('mixed slice', 'loc', slice(2,4,2), 'ix', slice(2,4,2), typs = ['mixed'], axes=0)

def test_loc_general(self):

Expand Down