@@ -2591,7 +2591,7 @@ def _partial_tup_index(self, tup, side="left"):
25912591 for k , (lab , lev , labs ) in enumerate (zipped ):
25922592 section = labs [start :end ]
25932593
2594- if lab not in lev :
2594+ if lab not in lev and not isna ( lab ) :
25952595 if not lev .is_type_compatible (lib .infer_dtype ([lab ], skipna = False )):
25962596 raise TypeError ("Level type mismatch: %s" % lab )
25972597
@@ -2601,13 +2601,44 @@ def _partial_tup_index(self, tup, side="left"):
26012601 loc -= 1
26022602 return start + section .searchsorted (loc , side = side )
26032603
2604- idx = lev . get_loc ( lab )
2604+ idx = self . _get_loc_single_level_index_wrapper ( lev , lab )
26052605 if k < n - 1 :
26062606 end = start + section .searchsorted (idx , side = "right" )
26072607 start = start + section .searchsorted (idx , side = "left" )
26082608 else :
26092609 return start + section .searchsorted (idx , side = side )
26102610
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+
26112642 def get_loc (self , key , method = None ):
26122643 """
26132644 Get location for a label or a tuple of labels as an integer, slice or
@@ -2668,7 +2699,8 @@ def _maybe_to_slice(loc):
26682699 mask [loc ] = True
26692700 return mask
26702701
2671- if not isinstance (key , tuple ):
2702+ if is_scalar (key ) or len (key ) == 1 :
2703+ # scalar value or a value in list
26722704 loc = self ._get_level_indexer (key , level = 0 )
26732705 return _maybe_to_slice (loc )
26742706
@@ -2707,7 +2739,9 @@ def _maybe_to_slice(loc):
27072739 loc = np .arange (start , stop , dtype = "int64" )
27082740
27092741 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+ )
27112745 if not mask .all ():
27122746 loc = loc [mask ]
27132747 if not len (loc ):
@@ -2934,8 +2968,7 @@ def convert_indexer(start, stop, step, indexer=indexer, codes=level_codes):
29342968 return slice (i , j , step )
29352969
29362970 else :
2937-
2938- code = level_index .get_loc (key )
2971+ code = self ._get_loc_single_level_index_wrapper (level_index , key )
29392972
29402973 if level > 0 or self .lexsort_depth == 0 :
29412974 # Desired level is not sorted
0 commit comments