Skip to content

Commit 71b9ea3

Browse files
stephenwlinwesm
authored andcommitted
BUG: Mismatch between get and set behavior for slices of floating indices
1 parent 9faec82 commit 71b9ea3

File tree

2 files changed

+64
-19
lines changed

2 files changed

+64
-19
lines changed

pandas/core/indexing.py

+25-19
Original file line numberDiff line numberDiff line change
@@ -435,23 +435,27 @@ def _convert_to_indexer(self, obj, axis=0):
435435
if isinstance(obj, slice):
436436
ltype = labels.inferred_type
437437

438-
if ltype == 'floating':
439-
int_slice = _is_int_slice(obj)
440-
else:
441-
# floats that are within tolerance of int used
442-
int_slice = _is_index_slice(obj)
438+
# in case of providing all floats, use label-based indexing
439+
float_slice = (labels.inferred_type == 'floating'
440+
and _is_float_slice(obj))
441+
442+
# floats that are within tolerance of int used as positions
443+
int_slice = _is_index_slice(obj)
443444

444445
null_slice = obj.start is None and obj.stop is None
445-
# could have integers in the first level of the MultiIndex
446+
447+
# could have integers in the first level of the MultiIndex,
448+
# in which case we wouldn't want to do position-based slicing
446449
position_slice = (int_slice
447450
and not ltype == 'integer'
448-
and not isinstance(labels, MultiIndex))
451+
and not isinstance(labels, MultiIndex)
452+
and not float_slice)
449453

450454
start, stop = obj.start, obj.stop
451455

452456
# last ditch effort: if we are mixed and have integers
453457
try:
454-
if 'mixed' in ltype and int_slice:
458+
if position_slice and 'mixed' in ltype:
455459
if start is not None:
456460
i = labels.get_loc(start)
457461
if stop is not None:
@@ -468,7 +472,7 @@ def _convert_to_indexer(self, obj, axis=0):
468472
indexer = labels.slice_indexer(start, stop, obj.step)
469473
except Exception:
470474
if _is_index_slice(obj):
471-
if labels.inferred_type == 'integer':
475+
if ltype == 'integer':
472476
raise
473477
indexer = obj
474478
else:
@@ -539,34 +543,36 @@ def _get_slice_axis(self, slice_obj, axis=0):
539543

540544
labels = obj._get_axis(axis)
541545

542-
int_slice = _is_index_slice(slice_obj)
543-
544-
start = slice_obj.start
545-
stop = slice_obj.stop
546+
ltype = labels.inferred_type
546547

547548
# in case of providing all floats, use label-based indexing
548549
float_slice = (labels.inferred_type == 'floating'
549550
and _is_float_slice(slice_obj))
550551

552+
# floats that are within tolerance of int used as positions
553+
int_slice = _is_index_slice(slice_obj)
554+
551555
null_slice = slice_obj.start is None and slice_obj.stop is None
552556

553-
# could have integers in the first level of the MultiIndex, in which
554-
# case we wouldn't want to do position-based slicing
557+
# could have integers in the first level of the MultiIndex,
558+
# in which case we wouldn't want to do position-based slicing
555559
position_slice = (int_slice
556-
and labels.inferred_type != 'integer'
560+
and not ltype == 'integer'
557561
and not isinstance(labels, MultiIndex)
558562
and not float_slice)
559563

564+
start, stop = slice_obj.start, slice_obj.stop
565+
560566
# last ditch effort: if we are mixed and have integers
561567
try:
562-
if 'mixed' in labels.inferred_type and int_slice:
568+
if position_slice and 'mixed' in ltype:
563569
if start is not None:
564570
i = labels.get_loc(start)
565571
if stop is not None:
566572
j = labels.get_loc(stop)
567573
position_slice = False
568574
except KeyError:
569-
if labels.inferred_type == 'mixed-integer-float':
575+
if ltype == 'mixed-integer-float':
570576
raise
571577

572578
if null_slice or position_slice:
@@ -576,7 +582,7 @@ def _get_slice_axis(self, slice_obj, axis=0):
576582
indexer = labels.slice_indexer(start, stop, slice_obj.step)
577583
except Exception:
578584
if _is_index_slice(slice_obj):
579-
if labels.inferred_type == 'integer':
585+
if ltype == 'integer':
580586
raise
581587
indexer = slice_obj
582588
else:

pandas/tests/test_frame.py

+39
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,45 @@ def test_getitem_setitem_float_labels(self):
11831183
self.assertRaises(Exception, df.ix.__getitem__, slice(1, 2))
11841184
self.assertRaises(Exception, df.ix.__setitem__, slice(1, 2), 0)
11851185

1186+
# #2727
1187+
index = Index([1.0, 2.5, 3.5, 4.5, 5.0])
1188+
df = DataFrame(np.random.randn(5, 5), index=index)
1189+
1190+
# positional slicing!
1191+
result = df.ix[1.0:5]
1192+
expected = df.reindex([2.5, 3.5, 4.5, 5.0])
1193+
assert_frame_equal(result, expected)
1194+
self.assertEqual(len(result), 4)
1195+
1196+
# positional again
1197+
result = df.ix[4:5]
1198+
expected = df.reindex([5.0])
1199+
assert_frame_equal(result, expected)
1200+
self.assertEqual(len(result), 1)
1201+
1202+
# label-based
1203+
result = df.ix[1.0:5.0]
1204+
expected = df.reindex([1.0, 2.5, 3.5, 4.5, 5.0])
1205+
assert_frame_equal(result, expected)
1206+
self.assertEqual(len(result), 5)
1207+
1208+
cp = df.copy()
1209+
# positional slicing!
1210+
cp.ix[1.0:5] = 0
1211+
self.assert_((cp.ix[1.0:5] == 0).values.all())
1212+
self.assert_((cp.ix[0:1] == df.ix[0:1]).values.all())
1213+
1214+
cp = df.copy()
1215+
# positional again
1216+
cp.ix[4:5] = 0
1217+
self.assert_((cp.ix[4:5] == 0).values.all())
1218+
self.assert_((cp.ix[0:4] == df.ix[0:4]).values.all())
1219+
1220+
cp = df.copy()
1221+
# label-based
1222+
cp.ix[1.0:5.0] = 0
1223+
self.assert_((cp.ix[1.0:5.0] == 0).values.all())
1224+
11861225
def test_setitem_single_column_mixed(self):
11871226
df = DataFrame(randn(5, 3), index=['a', 'b', 'c', 'd', 'e'],
11881227
columns=['foo', 'bar', 'baz'])

0 commit comments

Comments
 (0)