Skip to content

Commit 5592aaf

Browse files
committed
BUG: loc was failing on integer slices (incorrect implementation), GH 3053
1 parent 3e55bd7 commit 5592aaf

File tree

3 files changed

+48
-15
lines changed

3 files changed

+48
-15
lines changed

RELEASE.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pandas 0.11.0
3838
- Add ``squeeze`` function to reduce dimensionality of 1-len objects
3939
- Support slicing with time objects (GH2681_)
4040
- Added ``.iloc`` attribute, to support strict integer based indexing, analagous to ``.ix`` (GH2922_)
41-
- Added ``.loc`` attribute, to support strict label based indexing, analagous to ``.ix``
41+
- Added ``.loc`` attribute, to support strict label based indexing, analagous to ``.ix`` (GH3053_)
4242
- Added ``.iat`` attribute, to support fast scalar access via integers (replaces ``iget_value/iset_value``)
4343
- Added ``.at`` attribute, to support fast scalar access via labels (replaces ``get_value/set_value``)
4444
- Moved functionaility from ``irow,icol,iget_value/iset_value`` to ``.iloc`` indexer
@@ -183,6 +183,7 @@ pandas 0.11.0
183183
.. _GH3012: https://github.com/pydata/pandas/issues/3012
184184
.. _GH3029: https://github.com/pydata/pandas/issues/3029
185185
.. _GH3041: https://github.com/pydata/pandas/issues/3041
186+
.. _GH3053: https://github.com/pydata/pandas/issues/3053
186187

187188

188189
pandas 0.10.1

pandas/core/indexing.py

+15-8
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,19 @@ def _getbool_axis(self, key, axis=0):
647647
return self.obj.take(inds, axis=axis)
648648
except (Exception), detail:
649649
raise self._exception(detail)
650+
def _get_slice_axis(self, slice_obj, axis=0):
651+
""" this is pretty simple as we just have to deal with labels """
652+
obj = self.obj
653+
if not _need_slice(slice_obj):
654+
return obj
655+
656+
labels = obj._get_axis(axis)
657+
indexer = labels.slice_indexer(slice_obj.start, slice_obj.stop, slice_obj.step)
658+
659+
if isinstance(indexer, slice):
660+
return self._slice(indexer, axis=axis)
661+
else:
662+
return self.obj.take(indexer, axis=axis)
650663

651664
class _LocIndexer(_LocationIndexer):
652665
""" purely label based location based indexing """
@@ -667,11 +680,8 @@ def _has_valid_type(self, key, axis):
667680
if key.start not in ax:
668681
raise KeyError("start bound [%s] is not the [%s]" % (key.start,self.obj._get_axis_name(axis)))
669682
if key.stop is not None:
670-
stop = key.stop
671-
if com.is_integer(stop):
672-
stop -= 1
673-
if stop not in ax:
674-
raise KeyError("stop bound [%s] is not in the [%s]" % (stop,self.obj._get_axis_name(axis)))
683+
if key.stop not in ax:
684+
raise KeyError("stop bound [%s] is not in the [%s]" % (key.stop,self.obj._get_axis_name(axis)))
675685

676686
elif com._is_bool_indexer(key):
677687
return True
@@ -700,9 +710,6 @@ def _getitem_axis(self, key, axis=0):
700710
labels = self.obj._get_axis(axis)
701711

702712
if isinstance(key, slice):
703-
ltype = labels.inferred_type
704-
if ltype == 'mixed-integer-float' or ltype == 'mixed-integer':
705-
raise ValueError('cannot slice with a non-single type label array')
706713
return self._get_slice_axis(key, axis=axis)
707714
elif com._is_bool_indexer(key):
708715
return self._getbool_axis(key, axis=axis)

pandas/tests/test_indexing.py

+31-6
Original file line numberDiff line numberDiff line change
@@ -450,12 +450,38 @@ def test_loc_getitem_bool(self):
450450
def test_loc_getitem_int_slice(self):
451451

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

455455
# ok
456-
self.check_result('int slice2', 'loc', slice(2,5), 'ix', [2,4], typs = ['ints'], axes = 0)
457-
self.check_result('int slice2', 'loc', slice(3,7), 'ix', [3,6], typs = ['ints'], axes = 1)
458-
self.check_result('int slice2', 'loc', slice(4,9), 'ix', [4,8], typs = ['ints'], axes = 2)
456+
self.check_result('int slice2', 'loc', slice(2,4), 'ix', [2,4], typs = ['ints'], axes = 0)
457+
self.check_result('int slice2', 'loc', slice(3,6), 'ix', [3,6], typs = ['ints'], axes = 1)
458+
self.check_result('int slice2', 'loc', slice(4,8), 'ix', [4,8], typs = ['ints'], axes = 2)
459+
460+
# GH 3053
461+
# loc should treat integer slices like label slices
462+
from itertools import product
463+
464+
index = MultiIndex.from_tuples([t for t in product([6,7,8], ['a', 'b'])])
465+
df = DataFrame(np.random.randn(6, 6), index, index)
466+
result = df.loc[6:8,:]
467+
expected = df.ix[6:8,:]
468+
assert_frame_equal(result,expected)
469+
470+
index = MultiIndex.from_tuples([t for t in product([10, 20, 30], ['a', 'b'])])
471+
df = DataFrame(np.random.randn(6, 6), index, index)
472+
result = df.loc[20:30,:]
473+
expected = df.ix[20:30,:]
474+
assert_frame_equal(result,expected)
475+
476+
# doc examples
477+
result = df.loc[10,:]
478+
expected = df.ix[10,:]
479+
assert_frame_equal(result,expected)
480+
481+
result = df.loc[:,10]
482+
#expected = df.ix[:,10] (this fails)
483+
expected = df[10]
484+
assert_frame_equal(result,expected)
459485

460486
def test_loc_getitem_label_slice(self):
461487

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

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

481506
def test_loc_general(self):
482507

0 commit comments

Comments
 (0)