@@ -148,9 +148,7 @@ def name(self):
148
148
149
149
@property
150
150
def na_value (self ):
151
- if HAS_UNCERTAINTIES :
152
- return self .ureg .Quantity (_ufloat_nan , self .units )
153
- return self .ureg .Quantity (np .nan , self .units )
151
+ return self .ureg .Quantity (pd .NA , self .units )
154
152
155
153
def __hash__ (self ):
156
154
# make myself hashable
@@ -383,8 +381,7 @@ def isna(self):
383
381
if len (self ._data ) == 0 :
384
382
# True or False doesn't matter--we just need the value for the type
385
383
return np .full ((0 ), True )
386
- elif isinstance (self ._data [0 ], UFloat ):
387
- return unp .isnan (self ._data )
384
+ return self ._data .map (lambda x : pd .isna (x ) or (isinstance (x , UFloat ) and unp .isnan (x )))
388
385
return self ._data .isna ()
389
386
390
387
def astype (self , dtype , copy = True ):
@@ -537,6 +534,9 @@ def _from_sequence(cls, scalars, dtype=None, copy=False):
537
534
dtype = PintType (master_scalar .units )
538
535
539
536
def quantify_nan (item , promote_to_ufloat ):
537
+ if pd .isna (item ):
538
+ return dtype .ureg .Quantity (item , dtype .units )
539
+ # FIXME: most of this code is never executed (except the final return)
540
540
if promote_to_ufloat :
541
541
if type (item ) is UFloat :
542
542
return item * dtype .units
@@ -551,28 +551,31 @@ def quantify_nan(item, promote_to_ufloat):
551
551
return item
552
552
553
553
if isinstance (master_scalar , _Quantity ):
554
+ # A quantified master_scalar does not guarantee that we don't have NA and/or np.nan values in our scalars
554
555
if HAS_UNCERTAINTIES :
555
556
promote_to_ufloat = any (
556
- [isinstance (item .m , UFloat ) for item in scalars ]
557
+ [isinstance (item .m , UFloat ) for item in scalars if pd . notna ( item ) ]
557
558
)
558
559
else :
559
560
promote_to_ufloat = False
560
- scalars = [quantify_nan (item , promote_to_ufloat ) for item in scalars ]
561
+ scalars = [item if isinstance ( item , _Quantity ) else quantify_nan (item , promote_to_ufloat ) for item in scalars ]
561
562
scalars = [
562
563
(item .to (dtype .units ).magnitude if hasattr (item , "to" ) else item )
563
564
for item in scalars
564
565
]
565
- if HAS_UNCERTAINTIES :
566
+ elif HAS_UNCERTAINTIES :
566
567
promote_to_ufloat = any ([isinstance (item , UFloat ) for item in scalars ])
567
- if promote_to_ufloat :
568
- scalars = [
569
- item
570
- if isinstance (item , UFloat )
571
- else _ufloat_nan
572
- if np .isnan (item )
573
- else ufloat (item , 0 )
574
- for item in scalars
575
- ]
568
+ else :
569
+ promote_to_ufloat = False
570
+ if promote_to_ufloat :
571
+ scalars = [
572
+ item
573
+ if isinstance (item , UFloat )
574
+ else _ufloat_nan
575
+ if pd .isna (item )
576
+ else ufloat (item , 0 )
577
+ for item in scalars
578
+ ]
576
579
return cls (scalars , dtype = dtype , copy = copy )
577
580
578
581
@classmethod
@@ -642,7 +645,7 @@ def factorize(
642
645
643
646
codes = [- 1 ] * len (self .data )
644
647
# Note that item is a local variable provided in the loop below
645
- vf = np .vectorize (lambda x : x == item , otypes = [bool ])
648
+ vf = np .vectorize (lambda x : True if ( x_na := pd . isna ( x )) * ( item_na := pd . isna ( item )) else ( x_na == item_na and x == item ) , otypes = [bool ])
646
649
for code , item in enumerate (arr ):
647
650
code_mask = vf (self ._data )
648
651
codes = np .where (code_mask , code , codes )
@@ -663,7 +666,7 @@ def _values_for_factorize(self):
663
666
for item in arr :
664
667
if item not in unique_data :
665
668
unique_data .append (item )
666
- return np .array (unique_data ), _ufloat_nan
669
+ return np .array (unique_data ), pd . NA
667
670
return arr ._values_for_factorize ()
668
671
669
672
def value_counts (self , dropna = True ):
@@ -690,19 +693,16 @@ def value_counts(self, dropna=True):
690
693
691
694
# compute counts on the data with no nans
692
695
data = self ._data
696
+ nafilt = data .isna ()
697
+ na_value = pd .NA
698
+ data = data [~ nafilt ]
693
699
if HAS_UNCERTAINTIES and data .dtype .kind == "O" :
694
- nafilt = unp .isnan (data )
695
- na_value = _ufloat_nan
696
- data = data [~ nafilt ]
697
700
unique_data = []
698
701
for item in data :
699
702
if item not in unique_data :
700
703
unique_data .append (item )
701
704
index = list (unique_data )
702
705
else :
703
- nafilt = np .isnan (data )
704
- na_value = np .nan
705
- data = data [~ nafilt ]
706
706
index = list (set (data ))
707
707
708
708
data_list = data .tolist ()
@@ -883,7 +883,7 @@ def __array__(self, dtype=None, copy=False):
883
883
884
884
def _to_array_of_quantity (self , copy = False ):
885
885
qtys = [
886
- self ._Q (item , self ._dtype .units ) if not pd .isna ( item ) else item
886
+ self ._Q (item , self ._dtype .units ) if item is not pd .NA else item
887
887
for item in self ._data
888
888
]
889
889
with warnings .catch_warnings (record = True ):
0 commit comments