@@ -2591,7 +2591,7 @@ def _partial_tup_index(self, tup, side="left"):
2591
2591
for k , (lab , lev , labs ) in enumerate (zipped ):
2592
2592
section = labs [start :end ]
2593
2593
2594
- if lab not in lev :
2594
+ if lab not in lev and not isna ( lab ) :
2595
2595
if not lev .is_type_compatible (lib .infer_dtype ([lab ], skipna = False )):
2596
2596
raise TypeError ("Level type mismatch: %s" % lab )
2597
2597
@@ -2601,13 +2601,44 @@ def _partial_tup_index(self, tup, side="left"):
2601
2601
loc -= 1
2602
2602
return start + section .searchsorted (loc , side = side )
2603
2603
2604
- idx = lev . get_loc ( lab )
2604
+ idx = self . _get_loc_single_level_index_wrapper ( lev , lab )
2605
2605
if k < n - 1 :
2606
2606
end = start + section .searchsorted (idx , side = "right" )
2607
2607
start = start + section .searchsorted (idx , side = "left" )
2608
2608
else :
2609
2609
return start + section .searchsorted (idx , side = side )
2610
2610
2611
+ def _get_loc_single_level_index_wrapper (self , level_index : Index , key ) -> int :
2612
+ """
2613
+ Wrapper function for MultiIndex.
2614
+ If key is NA value, location of index unify as -1.
2615
+
2616
+ Parameters
2617
+ ----------
2618
+ level_index: Index
2619
+ Single level index in MultiIndex
2620
+ key : label
2621
+ If .get_loc key is tuple of labels,
2622
+ In this function, key is each level label
2623
+
2624
+ Returns
2625
+ -------
2626
+ loc : int
2627
+ If key is NA value, loc is -1
2628
+ Else, location of key in index.
2629
+
2630
+ See Also
2631
+ --------
2632
+ Index.get_loc : The get_loc method for (single-level) index.
2633
+
2634
+ Notes
2635
+ -----
2636
+ Depending on Index type, Handling NA value is different using get_loc.
2637
+ But in MultiIndex, NA values is denoted as missing by -1.
2638
+ """
2639
+
2640
+ return - 1 if isna (key ) else level_index .get_loc (key )
2641
+
2611
2642
def get_loc (self , key , method = None ):
2612
2643
"""
2613
2644
Get location for a label or a tuple of labels as an integer, slice or
@@ -2668,7 +2699,8 @@ def _maybe_to_slice(loc):
2668
2699
mask [loc ] = True
2669
2700
return mask
2670
2701
2671
- if not isinstance (key , tuple ):
2702
+ if is_scalar (key ) or len (key ) == 1 :
2703
+ # scalar value or a value in list
2672
2704
loc = self ._get_level_indexer (key , level = 0 )
2673
2705
return _maybe_to_slice (loc )
2674
2706
@@ -2707,7 +2739,9 @@ def _maybe_to_slice(loc):
2707
2739
loc = np .arange (start , stop , dtype = "int64" )
2708
2740
2709
2741
for i , k in enumerate (follow_key , len (lead_key )):
2710
- mask = self .codes [i ][loc ] == self .levels [i ].get_loc (k )
2742
+ mask = self .codes [i ][loc ] == self ._get_loc_single_level_index_wrapper (
2743
+ self .levels [i ], k
2744
+ )
2711
2745
if not mask .all ():
2712
2746
loc = loc [mask ]
2713
2747
if not len (loc ):
@@ -2934,8 +2968,7 @@ def convert_indexer(start, stop, step, indexer=indexer, codes=level_codes):
2934
2968
return slice (i , j , step )
2935
2969
2936
2970
else :
2937
-
2938
- code = level_index .get_loc (key )
2971
+ code = self ._get_loc_single_level_index_wrapper (level_index , key )
2939
2972
2940
2973
if level > 0 or self .lexsort_depth == 0 :
2941
2974
# Desired level is not sorted
0 commit comments