Skip to content

Commit 3be3444

Browse files
committed
COMPAT: fix warning for slice indexers when using floats in iloc that are convertible
1 parent 47409a0 commit 3be3444

File tree

4 files changed

+131
-64
lines changed

4 files changed

+131
-64
lines changed

pandas/core/index.py

+28-28
Original file line numberDiff line numberDiff line change
@@ -480,10 +480,10 @@ def to_int():
480480
if is_integer(key):
481481
return key
482482
elif is_float(key):
483-
if not self.is_floating():
484-
warnings.warn("scalar indexers for index type {0} should be integers and not floating point".format(
485-
type(self).__name__),FutureWarning)
486-
return to_int()
483+
key = to_int()
484+
warnings.warn("scalar indexers for index type {0} should be integers and not floating point".format(
485+
type(self).__name__),FutureWarning)
486+
return key
487487
return self._convert_indexer_error(key, 'label')
488488

489489
if is_float(key):
@@ -498,17 +498,9 @@ def _validate_slicer(self, key, f):
498498
""" validate and raise if needed on a slice indexers according to the
499499
passed in function """
500500

501-
if not f(key.start):
502-
self._convert_indexer_error(key.start, 'slice start value')
503-
if not f(key.stop):
504-
self._convert_indexer_error(key.stop, 'slice stop value')
505-
if not f(key.step):
506-
self._convert_indexer_error(key.step, 'slice step value')
507-
508-
def _convert_slice_indexer_iloc(self, key):
509-
""" convert a slice indexer for iloc only """
510-
self._validate_slicer(key, lambda v: v is None or is_integer(v))
511-
return key
501+
for c in ['start','stop','step']:
502+
if not f(getattr(key,c)):
503+
self._convert_indexer_error(key.start, 'slice {0} value'.format(c))
512504

513505
def _convert_slice_indexer_getitem(self, key, is_index_slice=False):
514506
""" called from the getitem slicers, determine how to treat the key
@@ -520,6 +512,25 @@ def _convert_slice_indexer_getitem(self, key, is_index_slice=False):
520512
def _convert_slice_indexer(self, key, typ=None):
521513
""" convert a slice indexer. disallow floats in the start/stop/step """
522514

515+
# validate iloc
516+
if typ == 'iloc':
517+
518+
# need to coerce to_int if needed
519+
def f(c):
520+
v = getattr(key,c)
521+
if v is None or is_integer(v):
522+
return v
523+
524+
# warn if its a convertible float
525+
if v == int(v):
526+
warnings.warn("slice indexers when using iloc should be integers "
527+
"and not floating point",FutureWarning)
528+
return int(v)
529+
530+
self._convert_indexer_error(v, 'slice {0} value'.format(c))
531+
532+
return slice(*[ f(c) for c in ['start','stop','step']])
533+
523534
# validate slicers
524535
def validate(v):
525536
if v is None or is_integer(v):
@@ -530,7 +541,6 @@ def validate(v):
530541
return False
531542

532543
return True
533-
534544
self._validate_slicer(key, validate)
535545

536546
# figure out if this is a positional indexer
@@ -543,9 +553,7 @@ def is_int(v):
543553
is_index_slice = is_int(start) and is_int(stop)
544554
is_positional = is_index_slice and not self.is_integer()
545555

546-
if typ == 'iloc':
547-
return self._convert_slice_indexer_iloc(key)
548-
elif typ == 'getitem':
556+
if typ == 'getitem':
549557
return self._convert_slice_indexer_getitem(
550558
key, is_index_slice=is_index_slice)
551559

@@ -1980,7 +1988,7 @@ def _convert_slice_indexer(self, key, typ=None):
19801988
""" convert a slice indexer, by definition these are labels
19811989
unless we are iloc """
19821990
if typ == 'iloc':
1983-
return self._convert_slice_indexer_iloc(key)
1991+
return super(Float64Index, self)._convert_slice_indexer(key, typ=typ)
19841992

19851993
# allow floats here
19861994
self._validate_slicer(
@@ -2386,14 +2394,6 @@ def __unicode__(self):
23862394
def __len__(self):
23872395
return len(self.labels[0])
23882396

2389-
def _convert_slice_indexer(self, key, typ=None):
2390-
""" convert a slice indexer. disallow floats in the start/stop/step """
2391-
2392-
if typ == 'iloc':
2393-
return self._convert_slice_indexer_iloc(key)
2394-
2395-
return super(MultiIndex, self)._convert_slice_indexer(key, typ=typ)
2396-
23972397
def _get_names(self):
23982398
return FrozenList(level.name for level in self.levels)
23992399

pandas/core/indexing.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import pandas.core.common as com
88
from pandas.core.common import (_is_bool_indexer, is_integer_dtype,
99
_asarray_tuplesafe, is_list_like, isnull,
10-
ABCSeries, ABCDataFrame, ABCPanel)
10+
ABCSeries, ABCDataFrame, ABCPanel, is_float)
1111
import pandas.lib as lib
1212

1313
import numpy as np
@@ -1319,6 +1319,7 @@ def _get_slice_axis(self, slice_obj, axis=0):
13191319
if not _need_slice(slice_obj):
13201320
return obj
13211321

1322+
slice_obj = self._convert_slice_indexer(slice_obj, axis)
13221323
if isinstance(slice_obj, slice):
13231324
return self._slice(slice_obj, axis=axis, typ='iloc')
13241325
else:
@@ -1363,7 +1364,15 @@ def _getitem_axis(self, key, axis=0, validate_iterable=False):
13631364

13641365
def _convert_to_indexer(self, obj, axis=0, is_setter=False):
13651366
""" much simpler as we only have to deal with our valid types """
1366-
if self._has_valid_type(obj, axis):
1367+
1368+
# make need to convert a float key
1369+
if isinstance(obj, slice):
1370+
return self._convert_slice_indexer(obj, axis)
1371+
1372+
elif is_float(obj):
1373+
return self._convert_scalar_indexer(obj, axis)
1374+
1375+
elif self._has_valid_type(obj, axis):
13671376
return obj
13681377

13691378
raise ValueError("Can only index by location with a [%s]" %

pandas/tests/test_frame.py

+21-7
Original file line numberDiff line numberDiff line change
@@ -1270,7 +1270,9 @@ def test_getitem_setitem_float_labels(self):
12701270
df = DataFrame(np.random.randn(5, 5), index=index)
12711271

12721272
# positional slicing only via iloc!
1273-
result = df.iloc[1.0:5]
1273+
with tm.assert_produces_warning(FutureWarning):
1274+
result = df.iloc[1.0:5]
1275+
12741276
expected = df.reindex([2.5, 3.5, 4.5, 5.0])
12751277
assert_frame_equal(result, expected)
12761278
self.assertEqual(len(result), 4)
@@ -1280,15 +1282,26 @@ def test_getitem_setitem_float_labels(self):
12801282
assert_frame_equal(result, expected)
12811283
self.assertEqual(len(result), 1)
12821284

1285+
# GH 4892, float indexers in iloc are deprecated
1286+
import warnings
1287+
warnings.filterwarnings(action='error', category=FutureWarning)
1288+
12831289
cp = df.copy()
1284-
cp.iloc[1.0:5] = 0
1285-
self.assert_((cp.iloc[1.0:5] == 0).values.all())
1286-
self.assert_((cp.iloc[0:1] == df.iloc[0:1]).values.all())
1290+
def f():
1291+
cp.iloc[1.0:5] = 0
1292+
self.assertRaises(FutureWarning, f)
1293+
def f():
1294+
result = cp.iloc[1.0:5] == 0
1295+
self.assertRaises(FutureWarning, f)
1296+
self.assertTrue(result.values.all())
1297+
self.assertTrue((cp.iloc[0:1] == df.iloc[0:1]).values.all())
1298+
1299+
warnings.filterwarnings(action='ignore', category=FutureWarning)
12871300

12881301
cp = df.copy()
12891302
cp.iloc[4:5] = 0
1290-
self.assert_((cp.iloc[4:5] == 0).values.all())
1291-
self.assert_((cp.iloc[0:4] == df.iloc[0:4]).values.all())
1303+
self.assertTrue((cp.iloc[4:5] == 0).values.all())
1304+
self.assertTrue((cp.iloc[0:4] == df.iloc[0:4]).values.all())
12921305

12931306
# float slicing
12941307
result = df.ix[1.0:5]
@@ -1313,7 +1326,8 @@ def test_getitem_setitem_float_labels(self):
13131326

13141327
cp = df.copy()
13151328
cp.ix[1.0:5.0] = 0
1316-
self.assert_((cp.ix[1.0:5.0] == 0).values.all())
1329+
result = cp.ix[1.0:5.0]
1330+
self.assertTrue((result == 0).values.all())
13171331

13181332
def test_setitem_single_column_mixed(self):
13191333
df = DataFrame(randn(5, 3), index=['a', 'b', 'c', 'd', 'e'],

pandas/tests/test_indexing.py

+71-27
Original file line numberDiff line numberDiff line change
@@ -3229,48 +3229,92 @@ def test_deprecate_float_indexers(self):
32293229
tm.makeDateIndex, tm.makePeriodIndex ]:
32303230

32313231
i = index(5)
3232+
3233+
for s in [ Series(np.arange(len(i)),index=i), DataFrame(np.random.randn(len(i),len(i)),index=i,columns=i) ]:
3234+
self.assertRaises(FutureWarning, lambda :
3235+
s.iloc[3.0])
3236+
3237+
# setting
3238+
def f():
3239+
s.iloc[3.0] = 0
3240+
self.assertRaises(FutureWarning, f)
3241+
3242+
# fallsback to position selection ,series only
32323243
s = Series(np.arange(len(i)),index=i)
3233-
self.assertRaises(FutureWarning, lambda :
3234-
s.iloc[3.0])
3244+
s[3]
32353245
self.assertRaises(FutureWarning, lambda :
32363246
s[3.0])
32373247

3238-
# this is ok!
3239-
s[3]
3240-
32413248
# ints
32423249
i = index(5)
3243-
s = Series(np.arange(len(i)))
3244-
self.assertRaises(FutureWarning, lambda :
3245-
s.iloc[3.0])
3250+
for s in [ Series(np.arange(len(i))), DataFrame(np.random.randn(len(i),len(i)),index=i,columns=i) ]:
3251+
self.assertRaises(FutureWarning, lambda :
3252+
s.iloc[3.0])
32463253

3247-
# on some arch's this doesn't provide a warning (and thus raise)
3248-
# and some it does
3249-
try:
3250-
s[3.0]
3251-
except:
3252-
pass
3254+
# on some arch's this doesn't provide a warning (and thus raise)
3255+
# and some it does
3256+
try:
3257+
s[3.0]
3258+
except:
3259+
pass
3260+
3261+
# setting
3262+
def f():
3263+
s.iloc[3.0] = 0
3264+
self.assertRaises(FutureWarning, f)
32533265

32543266
# floats: these are all ok!
32553267
i = np.arange(5.)
3256-
s = Series(np.arange(len(i)),index=i)
3257-
with tm.assert_produces_warning(False):
3258-
s[3.0]
32593268

3260-
with tm.assert_produces_warning(False):
3261-
s[3]
3269+
for s in [ Series(np.arange(len(i)),index=i), DataFrame(np.random.randn(len(i),len(i)),index=i,columns=i) ]:
3270+
with tm.assert_produces_warning(False):
3271+
s[3.0]
3272+
3273+
with tm.assert_produces_warning(False):
3274+
s[3]
3275+
3276+
self.assertRaises(FutureWarning, lambda :
3277+
s.iloc[3.0])
3278+
3279+
with tm.assert_produces_warning(False):
3280+
s.iloc[3]
3281+
3282+
with tm.assert_produces_warning(False):
3283+
s.loc[3.0]
32623284

3263-
with tm.assert_produces_warning(False):
3264-
s.iloc[3.0]
3285+
with tm.assert_produces_warning(False):
3286+
s.loc[3]
32653287

3266-
with tm.assert_produces_warning(False):
3267-
s.iloc[3]
3288+
def f():
3289+
s.iloc[3.0] = 0
3290+
self.assertRaises(FutureWarning, f)
32683291

3269-
with tm.assert_produces_warning(False):
3270-
s.loc[3.0]
3292+
# slices
3293+
for index in [ tm.makeIntIndex, tm.makeFloatIndex,
3294+
tm.makeStringIndex, tm.makeUnicodeIndex,
3295+
tm.makeDateIndex, tm.makePeriodIndex ]:
32713296

3272-
with tm.assert_produces_warning(False):
3273-
s.loc[3]
3297+
index = index(5)
3298+
for s in [ Series(range(5),index=index), DataFrame(np.random.randn(5,2),index=index) ]:
3299+
3300+
# getitem
3301+
self.assertRaises(FutureWarning, lambda :
3302+
s.iloc[3.0:4])
3303+
self.assertRaises(FutureWarning, lambda :
3304+
s.iloc[3.0:4.0])
3305+
self.assertRaises(FutureWarning, lambda :
3306+
s.iloc[3:4.0])
3307+
3308+
# setitem
3309+
def f():
3310+
s.iloc[3.0:4] = 0
3311+
self.assertRaises(FutureWarning, f)
3312+
def f():
3313+
s.iloc[3:4.0] = 0
3314+
self.assertRaises(FutureWarning, f)
3315+
def f():
3316+
s.iloc[3.0:4.0] = 0
3317+
self.assertRaises(FutureWarning, f)
32743318

32753319
warnings.filterwarnings(action='ignore', category=FutureWarning)
32763320

0 commit comments

Comments
 (0)