14
14
from pandas .lib import Timestamp
15
15
import pandas .lib as lib
16
16
import pandas ._period as plib
17
+ import pandas ._algos as _algos
17
18
18
19
19
20
#---------------
@@ -157,7 +158,8 @@ def __hash__(self):
157
158
def __add__ (self , other ):
158
159
if com .is_integer (other ):
159
160
return Period (ordinal = self .ordinal + other , freq = self .freq )
160
- raise ValueError ("Cannot add with non-integer value" )
161
+ else : # pragma: no cover
162
+ raise TypeError (other )
161
163
162
164
def __sub__ (self , other ):
163
165
if com .is_integer (other ):
@@ -167,7 +169,8 @@ def __sub__(self, other):
167
169
raise ValueError ("Cannot do arithmetic with "
168
170
"non-conforming periods" )
169
171
return self .ordinal - other .ordinal
170
- raise ValueError ("Cannot sub with non-integer value" )
172
+ else : # pragma: no cover
173
+ raise TypeError (other )
171
174
172
175
def asfreq (self , freq = None , how = 'E' ):
173
176
"""
@@ -188,9 +191,6 @@ def asfreq(self, freq=None, how='E'):
188
191
if mult2 != 1 :
189
192
raise ValueError ('Only mult == 1 supported' )
190
193
191
- if how not in ('S' , 'E' ):
192
- raise ValueError ('relation argument must be one of S or E' )
193
-
194
194
end = how == 'E'
195
195
new_ordinal = plib .period_asfreq (self .ordinal , base1 , base2 , end )
196
196
@@ -441,18 +441,10 @@ def _period_unbox(key, check=None):
441
441
return np .int64 (key .ordinal )
442
442
443
443
def _period_unbox_array (arr , check = None ):
444
- if arr is None :
445
- return arr
446
444
unboxer = np .frompyfunc (lambda x : _period_unbox (x , check = check ), 1 , 1 )
447
445
return unboxer (arr )
448
446
449
447
def _period_box_array (arr , freq ):
450
- if arr is None :
451
- return arr
452
-
453
- if not isinstance (arr , np .ndarray ):
454
- return arr
455
-
456
448
boxfunc = lambda x : Period (ordinal = x , freq = freq )
457
449
boxer = np .frompyfunc (boxfunc , 1 , 1 )
458
450
return boxer (arr )
@@ -461,14 +453,7 @@ def dt64arr_to_periodarr(data, freq):
461
453
if data .dtype != np .dtype ('M8[ns]' ):
462
454
raise ValueError ('Wrong dtype: %s' % data .dtype )
463
455
464
- if data is None :
465
- return data
466
-
467
- if isinstance (freq , basestring ):
468
- base , mult = _gfc (freq )
469
- else :
470
- base , mult = freq
471
-
456
+ base , mult = _gfc (freq )
472
457
return plib .dt64arr_to_periodarr (data .view ('i8' ), base )
473
458
474
459
# --- Period index sketch
@@ -490,12 +475,11 @@ def wrapper(self, other):
490
475
other = Period (other , freq = self .freq )
491
476
func = getattr (self .values , opname )
492
477
result = func (other .ordinal )
493
- try :
494
- return result .view (np .ndarray )
495
- except :
496
- return result
478
+
479
+ return result
497
480
return wrapper
498
481
482
+ _INT64_DTYPE = np .dtype (np .int64 )
499
483
500
484
class PeriodIndex (Int64Index ):
501
485
"""
@@ -560,10 +544,7 @@ def __new__(cls, data=None, ordinal=None,
560
544
year = None , month = None , quarter = None , day = None ,
561
545
hour = None , minute = None , second = None ):
562
546
563
- if isinstance (freq , Period ):
564
- freq = freq .freq
565
- else :
566
- freq = _freq_mod .get_standard_freq (freq )
547
+ freq = _freq_mod .get_standard_freq (freq )
567
548
568
549
if periods is not None :
569
550
if com .is_float (periods ):
@@ -598,9 +579,9 @@ def _generate_range(cls, start, end, periods, freq, fields):
598
579
'or endpoints, but not both' )
599
580
subarr , freq = _get_ordinal_range (start , end , periods , freq )
600
581
elif field_count > 0 :
601
- y , m , q , d , h , m , s = fields
602
- subarr , freq = _range_from_fields (year = y , month = m , quarter = q ,
603
- day = d , hour = h , minute = m ,
582
+ y , mth , q , d , h , minute , s = fields
583
+ subarr , freq = _range_from_fields (year = y , month = mth , quarter = q ,
584
+ day = d , hour = h , minute = minute ,
604
585
second = s , freq = freq )
605
586
else :
606
587
raise ValueError ('Not enough parameters to construct '
@@ -611,15 +592,11 @@ def _generate_range(cls, start, end, periods, freq, fields):
611
592
@classmethod
612
593
def _from_arraylike (cls , data , freq ):
613
594
if not isinstance (data , np .ndarray ):
614
- if np .isscalar (data ):
595
+ if np .isscalar (data ) or isinstance ( data , Period ) :
615
596
raise ValueError ('PeriodIndex() must be called with a '
616
597
'collection of some kind, %s was passed'
617
598
% repr (data ))
618
599
619
- elif isinstance (data , Period ):
620
- raise ValueError ('Data must be array of dates, strings, '
621
- 'or Period objects' )
622
-
623
600
# other iterable of some kind
624
601
if not isinstance (data , (list , tuple )):
625
602
data = list (data )
@@ -648,7 +625,7 @@ def _from_arraylike(cls, data, freq):
648
625
data = plib .period_asfreq_arr (data .values , base1 , base2 , 1 )
649
626
else :
650
627
if freq is None and len (data ) > 0 :
651
- freq = getattr (data [0 ], 'freq' )
628
+ freq = getattr (data [0 ], 'freq' , None )
652
629
653
630
if freq is None :
654
631
raise ValueError (('freq not specified and cannot be '
@@ -684,7 +661,10 @@ def astype(self, dtype):
684
661
result = np .empty (len (self ), dtype = dtype )
685
662
result [:] = [x for x in self ]
686
663
return result
687
- return np .ndarray .astype (self .values , dtype )
664
+ elif dtype == _INT64_DTYPE :
665
+ return self .values .copy ()
666
+ else : # pragma: no cover
667
+ raise ValueError ('Cannot cast PeriodIndex to dtype %s' % dtype )
688
668
689
669
def __iter__ (self ):
690
670
for val in self .values :
@@ -717,18 +697,11 @@ def asfreq(self, freq=None, how='E'):
717
697
freq = _freq_mod .get_standard_freq (freq )
718
698
719
699
base1 , mult1 = _gfc (self .freq )
720
-
721
- if isinstance (freq , basestring ):
722
- base2 , mult2 = _gfc (freq )
723
- else :
724
- base2 , mult2 = freq
700
+ base2 , mult2 = _gfc (freq )
725
701
726
702
if mult2 != 1 :
727
703
raise ValueError ('Only mult == 1 supported' )
728
704
729
- if how not in ('S' , 'E' ):
730
- raise ValueError ('relation argument must be one of S or E' )
731
-
732
705
end = how == 'E'
733
706
new_data = plib .period_asfreq_arr (self .values , base1 , base2 , end )
734
707
@@ -753,11 +726,12 @@ def asfreq(self, freq=None, how='E'):
753
726
754
727
# Try to run function on index first, and then on elements of index
755
728
# Especially important for group-by functionality
756
- def map (self , func_to_map ):
729
+ def map (self , f ):
757
730
try :
758
- return func_to_map (self )
731
+ return f (self )
759
732
except :
760
- return super (PeriodIndex , self ).map (func_to_map )
733
+ values = np .asarray (list (self ), dtype = object )
734
+ return _algos .arrmap_object (values , f )
761
735
762
736
def _mpl_repr (self ):
763
737
# how to represent ourselves to matplotlib
@@ -810,19 +784,10 @@ def shift(self, n):
810
784
return PeriodIndex (data = self .values + n , freq = self .freq )
811
785
812
786
def __add__ (self , other ):
813
- if com .is_integer (other ):
814
- return PeriodIndex (ordinal = self .values + other , freq = self .freq )
815
- return super (PeriodIndex , self ).__add__ (other )
787
+ return PeriodIndex (ordinal = self .values + other , freq = self .freq )
816
788
817
789
def __sub__ (self , other ):
818
- if com .is_integer (other ):
819
- return PeriodIndex (ordinal = self .values - other , freq = self .freq )
820
- if isinstance (other , Period ):
821
- if other .freq != self .freq :
822
- raise ValueError ("Cannot do arithmetic with "
823
- "non-conforming periods" )
824
- return PeriodIndex (self .values - other .ordinal )
825
- return super (PeriodIndex , self ).__sub__ (other )
790
+ return PeriodIndex (ordinal = self .values - other , freq = self .freq )
826
791
827
792
@property
828
793
def inferred_type (self ):
@@ -843,11 +808,17 @@ def get_value(self, series, key):
843
808
grp = _freq_mod ._infer_period_group (reso )
844
809
freqn = _freq_mod ._period_group (self .freq )
845
810
811
+ vals = self .values
812
+
846
813
# if our data is higher resolution than requested key, slice
847
814
if grp < freqn :
848
815
iv = Period (asdt , freq = (grp ,1 ))
849
816
ord1 = iv .asfreq (self .freq , how = 'S' ).ordinal
850
817
ord2 = iv .asfreq (self .freq , how = 'E' ).ordinal
818
+
819
+ if ord2 < vals [0 ] or ord1 > vals [- 1 ]:
820
+ raise KeyError (key )
821
+
851
822
pos = np .searchsorted (self .values , [ord1 , ord2 ])
852
823
key = slice (pos [0 ], pos [1 ]+ 1 )
853
824
return series [key ]
@@ -858,9 +829,6 @@ def get_value(self, series, key):
858
829
pass
859
830
except KeyError :
860
831
pass
861
- except IndexError :
862
- ival = Period (key , freq = self .freq )
863
- raise IndexError ("%s is out of bounds" % ival )
864
832
865
833
key = to_period (key , self .freq )
866
834
return self ._engine .get_value (series , key .ordinal )
@@ -881,8 +849,6 @@ def get_loc(self, key):
881
849
key = asdt
882
850
except TypeError :
883
851
pass
884
- except KeyError :
885
- pass
886
852
887
853
key = to_period (key , self .freq ).ordinal
888
854
return self ._engine .get_loc (key )
@@ -904,7 +870,7 @@ def join(self, other, how='left', level=None, return_indexers=False):
904
870
905
871
def _assert_can_do_setop (self , other ):
906
872
if not isinstance (other , PeriodIndex ):
907
- raise TypeError ('can only call with other PeriodIndex-ed objects' )
873
+ raise ValueError ('can only call with other PeriodIndex-ed objects' )
908
874
909
875
if self .freq != other .freq :
910
876
raise ValueError ('Only like-indexed PeriodIndexes compatible '
@@ -933,7 +899,10 @@ def __getitem__(self, key):
933
899
934
900
result = arr_idx [key ]
935
901
if result .ndim > 1 :
936
- return PeriodIndex (result , name = self .name , freq = self .freq )
902
+ values = PeriodIndex (result .squeeze (), name = self .name ,
903
+ freq = self .freq )
904
+ values = np .asarray (list (values ), dtype = object )
905
+ return values .reshape (result .shape )
937
906
938
907
return PeriodIndex (result , name = self .name , freq = self .freq )
939
908
@@ -948,12 +917,6 @@ def format(self, name=False):
948
917
949
918
return header + ['%s' % Period (x , freq = self .freq ) for x in self ]
950
919
951
- def _view_like (self , ndarray ):
952
- result = ndarray .view (type (self ))
953
- result .freq = self .freq
954
- result .name = self .name
955
- return result
956
-
957
920
def __array_finalize__ (self , obj ):
958
921
if self .ndim == 0 : # pragma: no cover
959
922
return self .item ()
@@ -988,11 +951,6 @@ def _get_ordinal_range(start, end, periods, freq):
988
951
989
952
is_start_per = isinstance (start , Period )
990
953
is_end_per = isinstance (end , Period )
991
- if (start is not None and not is_start_per ):
992
- raise ValueError ('Failed to convert %s to period' % start )
993
-
994
- if (end is not None and not is_end_per ):
995
- raise ValueError ('Failed to convert %s to period' % end )
996
954
997
955
if is_start_per and is_end_per and (start .freq != end .freq ):
998
956
raise ValueError ('Start and end must have same freq' )
@@ -1002,7 +960,7 @@ def _get_ordinal_range(start, end, periods, freq):
1002
960
freq = start .freq
1003
961
elif is_end_per :
1004
962
freq = end .freq
1005
- else :
963
+ else : # pragma: no cover
1006
964
raise ValueError ('Could not infer freq from start/end' )
1007
965
1008
966
if periods is not None :
@@ -1014,9 +972,6 @@ def _get_ordinal_range(start, end, periods, freq):
1014
972
data = np .arange (start .ordinal , start .ordinal + periods ,
1015
973
dtype = np .int64 )
1016
974
else :
1017
- if start is None or end is None :
1018
- msg = 'Must specify both start and end if periods is None'
1019
- raise ValueError (msg )
1020
975
data = np .arange (start .ordinal , end .ordinal + 1 , dtype = np .int64 )
1021
976
1022
977
return data , freq
@@ -1055,8 +1010,8 @@ def _range_from_fields(year=None, month=None, quarter=None, day=None,
1055
1010
raise ValueError ('Only mult == 1 supported' )
1056
1011
1057
1012
arrays = _make_field_arrays (year , month , day , hour , minute , second )
1058
- for y , m , d , h , m , s in zip (* arrays ):
1059
- ordinals .append (plib .period_ordinal (y , m , d , h , m , s , base ))
1013
+ for y , mth , d , h , mn , s in zip (* arrays ):
1014
+ ordinals .append (plib .period_ordinal (y , mth , d , h , mn , s , base ))
1060
1015
1061
1016
return np .array (ordinals , dtype = np .int64 ), freq
1062
1017
@@ -1066,6 +1021,8 @@ def _make_field_arrays(*fields):
1066
1021
if isinstance (x , (list , np .ndarray )):
1067
1022
if length is not None and len (x ) != length :
1068
1023
raise ValueError ('Mismatched Period array lengths' )
1024
+ elif length is None :
1025
+ length = len (x )
1069
1026
1070
1027
arrays = [np .asarray (x ) if isinstance (x , (np .ndarray , list ))
1071
1028
else np .repeat (x , length ) for x in fields ]
0 commit comments