1
1
""" define the IntervalIndex """
2
2
3
3
import numpy as np
4
+ import warnings
4
5
5
6
from pandas .core .dtypes .missing import notna , isna
6
7
from pandas .core .dtypes .generic import ABCDatetimeIndex , ABCPeriodIndex
@@ -151,6 +152,10 @@ class IntervalIndex(IntervalMixin, Index):
151
152
Name to be stored in the index.
152
153
copy : boolean, default False
153
154
Copy the meta-data
155
+ dtype : dtype or None, default None
156
+ If None, dtype will be inferred
157
+
158
+ ..versionadded:: 0.23.0
154
159
155
160
Attributes
156
161
----------
@@ -167,7 +172,6 @@ class IntervalIndex(IntervalMixin, Index):
167
172
from_arrays
168
173
from_tuples
169
174
from_breaks
170
- from_intervals
171
175
contains
172
176
173
177
Examples
@@ -181,8 +185,7 @@ class IntervalIndex(IntervalMixin, Index):
181
185
182
186
It may also be constructed using one of the constructor
183
187
methods: :meth:`IntervalIndex.from_arrays`,
184
- :meth:`IntervalIndex.from_breaks`, :meth:`IntervalIndex.from_intervals`
185
- and :meth:`IntervalIndex.from_tuples`.
188
+ :meth:`IntervalIndex.from_breaks`, and :meth:`IntervalIndex.from_tuples`.
186
189
187
190
See further examples in the doc strings of ``interval_range`` and the
188
191
mentioned constructor methods.
@@ -211,8 +214,7 @@ class IntervalIndex(IntervalMixin, Index):
211
214
212
215
_mask = None
213
216
214
- def __new__ (cls , data , closed = None ,
215
- name = None , copy = False , dtype = None ,
217
+ def __new__ (cls , data , closed = None , name = None , copy = False , dtype = None ,
216
218
fastpath = False , verify_integrity = True ):
217
219
218
220
if fastpath :
@@ -245,19 +247,28 @@ def __new__(cls, data, closed=None,
245
247
246
248
closed = closed or infer_closed
247
249
248
- return cls ._simple_new (left , right , closed , name ,
249
- copy = copy , verify_integrity = verify_integrity )
250
+ return cls ._simple_new (left , right , closed , name , copy = copy ,
251
+ dtype = dtype , verify_integrity = verify_integrity )
250
252
251
253
@classmethod
252
- def _simple_new (cls , left , right , closed = None , name = None ,
253
- copy = False , verify_integrity = True ):
254
+ def _simple_new (cls , left , right , closed = None , name = None , copy = False ,
255
+ dtype = None , verify_integrity = True ):
254
256
result = IntervalMixin .__new__ (cls )
255
257
256
- if closed is None :
257
- closed = 'right'
258
+ closed = closed or 'right'
258
259
left = _ensure_index (left , copy = copy )
259
260
right = _ensure_index (right , copy = copy )
260
261
262
+ if dtype is not None :
263
+ # GH 19262: dtype must be an IntervalDtype to override inferred
264
+ dtype = pandas_dtype (dtype )
265
+ if not is_interval_dtype (dtype ):
266
+ msg = 'dtype must be an IntervalDtype, got {dtype}'
267
+ raise TypeError (msg .format (dtype = dtype ))
268
+ elif dtype .subtype is not None :
269
+ left = left .astype (dtype .subtype )
270
+ right = right .astype (dtype .subtype )
271
+
261
272
# coerce dtypes to match if needed
262
273
if is_float_dtype (left ) and is_integer_dtype (right ):
263
274
right = right .astype (left .dtype )
@@ -304,7 +315,7 @@ def _shallow_copy(self, left=None, right=None, **kwargs):
304
315
# only single value passed, could be an IntervalIndex
305
316
# or array of Intervals
306
317
if not isinstance (left , IntervalIndex ):
307
- left = type ( self ). from_intervals (left )
318
+ left = self . _constructor (left )
308
319
309
320
left , right = left .left , left .right
310
321
else :
@@ -322,7 +333,7 @@ def _validate(self):
322
333
Verify that the IntervalIndex is valid.
323
334
"""
324
335
if self .closed not in _VALID_CLOSED :
325
- raise ValueError ("invalid options for 'closed': {closed}"
336
+ raise ValueError ("invalid option for 'closed': {closed}"
326
337
.format (closed = self .closed ))
327
338
if len (self .left ) != len (self .right ):
328
339
raise ValueError ('left and right must have the same length' )
@@ -356,7 +367,7 @@ def _engine(self):
356
367
357
368
@property
358
369
def _constructor (self ):
359
- return type (self ). from_intervals
370
+ return type (self )
360
371
361
372
def __contains__ (self , key ):
362
373
"""
@@ -402,7 +413,8 @@ def contains(self, key):
402
413
return False
403
414
404
415
@classmethod
405
- def from_breaks (cls , breaks , closed = 'right' , name = None , copy = False ):
416
+ def from_breaks (cls , breaks , closed = 'right' , name = None , copy = False ,
417
+ dtype = None ):
406
418
"""
407
419
Construct an IntervalIndex from an array of splits
408
420
@@ -417,6 +429,10 @@ def from_breaks(cls, breaks, closed='right', name=None, copy=False):
417
429
Name to be stored in the index.
418
430
copy : boolean, default False
419
431
copy the data
432
+ dtype : dtype or None, default None
433
+ If None, dtype will be inferred
434
+
435
+ ..versionadded:: 0.23.0
420
436
421
437
Examples
422
438
--------
@@ -430,18 +446,17 @@ def from_breaks(cls, breaks, closed='right', name=None, copy=False):
430
446
interval_range : Function to create a fixed frequency IntervalIndex
431
447
IntervalIndex.from_arrays : Construct an IntervalIndex from a left and
432
448
right array
433
- IntervalIndex.from_intervals : Construct an IntervalIndex from an array
434
- of Interval objects
435
449
IntervalIndex.from_tuples : Construct an IntervalIndex from a
436
450
list/array of tuples
437
451
"""
438
452
breaks = maybe_convert_platform_interval (breaks )
439
453
440
454
return cls .from_arrays (breaks [:- 1 ], breaks [1 :], closed ,
441
- name = name , copy = copy )
455
+ name = name , copy = copy , dtype = dtype )
442
456
443
457
@classmethod
444
- def from_arrays (cls , left , right , closed = 'right' , name = None , copy = False ):
458
+ def from_arrays (cls , left , right , closed = 'right' , name = None , copy = False ,
459
+ dtype = None ):
445
460
"""
446
461
Construct an IntervalIndex from a a left and right array
447
462
@@ -458,6 +473,10 @@ def from_arrays(cls, left, right, closed='right', name=None, copy=False):
458
473
Name to be stored in the index.
459
474
copy : boolean, default False
460
475
copy the data
476
+ dtype : dtype or None, default None
477
+ If None, dtype will be inferred
478
+
479
+ ..versionadded:: 0.23.0
461
480
462
481
Examples
463
482
--------
@@ -471,22 +490,23 @@ def from_arrays(cls, left, right, closed='right', name=None, copy=False):
471
490
interval_range : Function to create a fixed frequency IntervalIndex
472
491
IntervalIndex.from_breaks : Construct an IntervalIndex from an array of
473
492
splits
474
- IntervalIndex.from_intervals : Construct an IntervalIndex from an array
475
- of Interval objects
476
493
IntervalIndex.from_tuples : Construct an IntervalIndex from a
477
494
list/array of tuples
478
495
"""
479
496
left = maybe_convert_platform_interval (left )
480
497
right = maybe_convert_platform_interval (right )
481
498
482
- return cls ._simple_new (left , right , closed , name = name ,
483
- copy = copy , verify_integrity = True )
499
+ return cls ._simple_new (left , right , closed , name = name , copy = copy ,
500
+ dtype = dtype , verify_integrity = True )
484
501
485
502
@classmethod
486
- def from_intervals (cls , data , name = None , copy = False ):
503
+ def from_intervals (cls , data , closed = None , name = None , copy = False ,
504
+ dtype = None ):
487
505
"""
488
506
Construct an IntervalIndex from a 1d array of Interval objects
489
507
508
+ .. deprecated:: 0.23.0
509
+
490
510
Parameters
491
511
----------
492
512
data : array-like (1-dimensional)
@@ -496,6 +516,10 @@ def from_intervals(cls, data, name=None, copy=False):
496
516
Name to be stored in the index.
497
517
copy : boolean, default False
498
518
by-default copy the data, this is compat only and ignored
519
+ dtype : dtype or None, default None
520
+ If None, dtype will be inferred
521
+
522
+ ..versionadded:: 0.23.0
499
523
500
524
Examples
501
525
--------
@@ -521,16 +545,14 @@ def from_intervals(cls, data, name=None, copy=False):
521
545
IntervalIndex.from_tuples : Construct an IntervalIndex from a
522
546
list/array of tuples
523
547
"""
524
- if isinstance (data , IntervalIndex ):
525
- left , right , closed = data .left , data .right , data .closed
526
- name = name or data .name
527
- else :
528
- data = maybe_convert_platform_interval (data )
529
- left , right , closed = intervals_to_interval_bounds (data )
530
- return cls .from_arrays (left , right , closed , name = name , copy = False )
548
+ msg = ('IntervalIndex.from_intervals is deprecated and will be '
549
+ 'removed in a future version; use IntervalIndex(...) instead' )
550
+ warnings .warn (msg , FutureWarning , stacklevel = 2 )
551
+ return cls (data , closed = closed , name = name , copy = copy , dtype = dtype )
531
552
532
553
@classmethod
533
- def from_tuples (cls , data , closed = 'right' , name = None , copy = False ):
554
+ def from_tuples (cls , data , closed = 'right' , name = None , copy = False ,
555
+ dtype = None ):
534
556
"""
535
557
Construct an IntervalIndex from a list/array of tuples
536
558
@@ -545,10 +567,14 @@ def from_tuples(cls, data, closed='right', name=None, copy=False):
545
567
Name to be stored in the index.
546
568
copy : boolean, default False
547
569
by-default copy the data, this is compat only and ignored
570
+ dtype : dtype or None, default None
571
+ If None, dtype will be inferred
572
+
573
+ ..versionadded:: 0.23.0
548
574
549
575
Examples
550
576
--------
551
- >>> pd.IntervalIndex.from_tuples([(0, 1), (1,2)])
577
+ >>> pd.IntervalIndex.from_tuples([(0, 1), (1, 2)])
552
578
IntervalIndex([(0, 1], (1, 2]],
553
579
closed='right', dtype='interval[int64]')
554
580
@@ -559,8 +585,6 @@ def from_tuples(cls, data, closed='right', name=None, copy=False):
559
585
right array
560
586
IntervalIndex.from_breaks : Construct an IntervalIndex from an array of
561
587
splits
562
- IntervalIndex.from_intervals : Construct an IntervalIndex from an array
563
- of Interval objects
564
588
"""
565
589
if len (data ):
566
590
left , right = [], []
@@ -571,15 +595,22 @@ def from_tuples(cls, data, closed='right', name=None, copy=False):
571
595
if isna (d ):
572
596
lhs = rhs = np .nan
573
597
else :
574
- lhs , rhs = d
598
+ try :
599
+ # need list of length 2 tuples, e.g. [(0, 1), (1, 2), ...]
600
+ lhs , rhs = d
601
+ except ValueError :
602
+ msg = ('IntervalIndex.from_tuples requires tuples of '
603
+ 'length 2, got {tpl}' ).format (tpl = d )
604
+ raise ValueError (msg )
605
+ except TypeError :
606
+ msg = ('IntervalIndex.from_tuples received an invalid '
607
+ 'item, {tpl}' ).format (tpl = d )
608
+ raise TypeError (msg )
575
609
left .append (lhs )
576
610
right .append (rhs )
577
611
578
- # TODO
579
- # if we have nulls and we previous had *only*
580
- # integer data, then we have changed the dtype
581
-
582
- return cls .from_arrays (left , right , closed , name = name , copy = False )
612
+ return cls .from_arrays (left , right , closed , name = name , copy = False ,
613
+ dtype = dtype )
583
614
584
615
def to_tuples (self , na_tuple = True ):
585
616
"""
@@ -921,7 +952,7 @@ def get_loc(self, key, method=None):
921
952
Examples
922
953
---------
923
954
>>> i1, i2 = pd.Interval(0, 1), pd.Interval(1, 2)
924
- >>> index = pd.IntervalIndex.from_intervals ([i1, i2])
955
+ >>> index = pd.IntervalIndex([i1, i2])
925
956
>>> index.get_loc(1)
926
957
0
927
958
@@ -937,7 +968,7 @@ def get_loc(self, key, method=None):
937
968
relevant intervals.
938
969
939
970
>>> i3 = pd.Interval(0, 2)
940
- >>> overlapping_index = pd.IntervalIndex.from_intervals ([i2, i3])
971
+ >>> overlapping_index = pd.IntervalIndex([i2, i3])
941
972
>>> overlapping_index.get_loc(1.5)
942
973
array([0, 1], dtype=int64)
943
974
"""
0 commit comments