Skip to content

Commit 05bd9d6

Browse files
committed
BUG: label slicing bugs with floats in Series, DataFrame, close #1167
1 parent 6bf6274 commit 05bd9d6

File tree

5 files changed

+68
-9
lines changed

5 files changed

+68
-9
lines changed

RELEASE.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ pandas 0.8.0
5656
- Series([False, nan]) was getting casted to float64 (GH #1074)
5757
- Fix binary operations between boolean Series and object Series with
5858
booleans and NAs (GH #1074)
59+
- Couldn't assign whole array to column in mixed-type DataFrame via .ix
60+
(#1142)
5961

6062
pandas 0.7.3
6163
============

pandas/core/frame.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,11 +1440,13 @@ def __getitem__(self, key):
14401440
# slice rows
14411441
if isinstance(key, slice):
14421442
from pandas.core.indexing import _is_index_slice
1443-
if self.index.inferred_type == 'integer' or _is_index_slice(key):
1443+
idx_type = self.index.inferred_type
1444+
if idx_type == 'floating':
1445+
indexer = self.ix._convert_to_indexer(key, axis=0)
1446+
elif idx_type == 'integer' or _is_index_slice(key):
14441447
indexer = key
14451448
else:
14461449
indexer = self.ix._convert_to_indexer(key, axis=0)
1447-
14481450
new_data = self._data.get_slice(indexer, axis=1)
14491451
return self._constructor(new_data)
14501452
# either boolean or fancy integer index

pandas/core/indexing.py

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -251,26 +251,32 @@ def _convert_to_indexer(self, obj, axis=0):
251251
pass
252252

253253
if isinstance(obj, slice):
254+
ltype = labels.inferred_type
255+
256+
if ltype == 'floating':
257+
int_slice = _is_int_slice(obj)
258+
else:
259+
# floats that are within tolerance of int used
260+
int_slice = _is_index_slice(obj)
254261

255-
int_slice = _is_index_slice(obj)
256262
null_slice = obj.start is None and obj.stop is None
257263
# could have integers in the first level of the MultiIndex
258264
position_slice = (int_slice
259-
and not labels.inferred_type == 'integer'
265+
and not ltype == 'integer'
260266
and not isinstance(labels, MultiIndex))
261267

262268
start, stop = obj.start, obj.stop
263269

264270
# last ditch effort: if we are mixed and have integers
265271
try:
266-
if 'mixed' in labels.inferred_type and int_slice:
272+
if 'mixed' in ltype and int_slice:
267273
if start is not None:
268274
i = labels.get_loc(start)
269275
if stop is not None:
270276
j = labels.get_loc(stop)
271277
position_slice = False
272278
except KeyError:
273-
if labels.inferred_type == 'mixed-integer':
279+
if ltype == 'mixed-integer':
274280
raise
275281

276282
if null_slice or position_slice:
@@ -337,8 +343,7 @@ def _get_slice_axis(self, slice_obj, axis=0):
337343

338344
# in case of providing all floats, use label-based indexing
339345
float_slice = (labels.inferred_type == 'floating'
340-
and (type(start) == float or start is None)
341-
and (type(stop) == float or stop is None))
346+
and _is_float_slice(slice_obj))
342347

343348
null_slice = slice_obj.start is None and slice_obj.stop is None
344349

@@ -395,6 +400,28 @@ def _crit(v):
395400

396401
return not both_none and (_crit(obj.start) and _crit(obj.stop))
397402

403+
def _is_int_slice(obj):
404+
def _is_valid_index(x):
405+
return com.is_integer(x)
406+
407+
def _crit(v):
408+
return v is None or _is_valid_index(v)
409+
410+
both_none = obj.start is None and obj.stop is None
411+
412+
return not both_none and (_crit(obj.start) and _crit(obj.stop))
413+
414+
def _is_float_slice(obj):
415+
def _is_valid_index(x):
416+
return com.is_float(x)
417+
418+
def _crit(v):
419+
return v is None or _is_valid_index(v)
420+
421+
both_none = obj.start is None and obj.stop is None
422+
423+
return not both_none and (_crit(obj.start) and _crit(obj.stop))
424+
398425

399426
class _SeriesIndexer(_NDFrameIndexer):
400427
"""

pandas/core/series.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,11 @@ def _get_with(self, key):
430430
if isinstance(key, slice):
431431
from pandas.core.indexing import _is_index_slice
432432

433-
if self.index.inferred_type == 'integer' or _is_index_slice(key):
433+
idx_type = self.index.inferred_type
434+
435+
if idx_type == 'floating':
436+
indexer = self.ix._convert_to_indexer(key, axis=0)
437+
elif idx_type == 'integer' or _is_index_slice(key):
434438
indexer = key
435439
else:
436440
indexer = self.ix._convert_to_indexer(key, axis=0)

pandas/tests/test_series.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,30 @@ def test_slice_floats2(self):
566566
self.assert_(len(s.ix[12.0:]) == 8)
567567
self.assert_(len(s.ix[12.5:]) == 7)
568568

569+
def test_slice_float64(self):
570+
values = np.arange(10., 50., 2)
571+
index = Index(values)
572+
573+
start, end = values[[5, 15]]
574+
575+
s = Series(np.random.randn(20), index=index)
576+
577+
result = s[start:end]
578+
expected = s.ix[5:16]
579+
assert_series_equal(result, expected)
580+
581+
result = s.ix[start:end]
582+
assert_series_equal(result, expected)
583+
584+
df = DataFrame(np.random.randn(20, 3), index=index)
585+
586+
result = df[start:end]
587+
expected = df.ix[5:16]
588+
tm.assert_frame_equal(result, expected)
589+
590+
result = df.ix[start:end]
591+
tm.assert_frame_equal(result, expected)
592+
569593
def test_setitem(self):
570594
self.ts[self.ts.index[5]] = np.NaN
571595
self.ts[[1,2,17]] = np.NaN

0 commit comments

Comments
 (0)