o
    5c                    @  s  d dl mZ d dlmZ d dlmZ d dlmZmZm	Z	m
Z
mZmZmZmZmZmZmZ d dlZd dlZd dlmZ d dlmZmZmZ d dlmZ d d	lm Z m!Z!m"Z"m#Z#m$Z$m%Z% d d
l&m'Z( d dl)m*Z*m+Z+m,Z, d dl-m.Z.m/Z/m0Z0m1Z1 d dl2m3Z3 d dl4m5Z5 d dl6m7Z7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z=m>Z>m?Z?m@Z@mAZA d dlBmCZC d dlDmEZEmFZFmGZG d dlHmIZImJZJ d dlKmL  mMZ d dlNmOZO d dlPmQZQ d dlRmL  mSZT d dlUmL  mV  mWZX d dlUmYZYmZZZm[Z[m\Z\ d dl]m^Z^ d dl_m`Z` d dlambZbmcZcmdZd d dlemfZf erd dlgmhZhmiZimjZj ekeXjlZlelmddd G dd dejnejoZpG d d! d!ejnejqZrdBd%d&ZsG d'd deYZtdCd,d-ZudDdEd0d1ZvdFd3d4ZwdGd7d8ZxdHdId=d>ZydJd@dAZzdS )K    )annotations)wraps	getsizeof)TYPE_CHECKINGAnyCallable
CollectionHashableIterableListLiteralSequenceTuplecastN)
get_option)algosindexlib)
duplicated)AnyArrayLikeDtypeObjFScalarShapenpt)function)InvalidIndexErrorPerformanceWarningUnsortedIndexError)Appendercache_readonlydeprecate_nonkeyword_argumentsdoc)find_stack_level)coerce_indexer_dtype)ensure_int64ensure_platform_intis_categorical_dtypeis_extension_array_dtypeis_hashable
is_integeris_iteratoris_list_likeis_object_dtype	is_scalarpandas_dtype)ExtensionDtype)ABCDataFrameABCDatetimeIndexABCTimedeltaIndex)array_equivalentisna)Categorical)factorize_from_iterables)Index_index_shared_docsensure_indexget_unanimous_names)
FrozenList)make_invalid_op)get_group_indexindexer_from_factorizedlexsort_indexer)pprint_thing)CategoricalIndex	DataFrameSeries
MultiIndexzMultiIndex or list of tuples)klasstarget_klassc                   @     e Zd ZdZejZdd ZdS )MultiIndexUIntEngineza
    This class manages a MultiIndex by mapping label combinations to positive
    integers.
    c                 C  s0   || j K }|jdkrtj|S tjj|ddS )a  
        Transform combination(s) of uint64 in one uint64 (each), in a strictly
        monotonic way (i.e. respecting the lexicographic order of integer
        combinations): see BaseMultiIndexCodesEngine documentation.

        Parameters
        ----------
        codes : 1- or 2-dimensional array of dtype uint64
            Combinations of integers (one per row)

        Returns
        -------
        scalar or 1-dimensional array, of dtype uint64
            Integer(s) representing one combination (each).
           axis)offsetsndimnp
bitwise_orreduceselfcodes rV   O/var/www/html/gps/gps/lib/python3.10/site-packages/pandas/core/indexes/multi.py_codes_to_intsw   s   

z#MultiIndexUIntEngine._codes_to_intsN)__name__
__module____qualname____doc__libindexUInt64Engine_baserX   rV   rV   rV   rW   rJ   o   s    rJ   c                   @  rI   )MultiIndexPyIntEnginez
    This class manages those (extreme) cases in which the number of possible
    label combinations overflows the 64 bits integers, and uses an ObjectEngine
    containing Python integers.
    c                 C  s6   | d| j> }|jdkrtj|S tjj|ddS )a  
        Transform combination(s) of uint64 in one Python integer (each), in a
        strictly monotonic way (i.e. respecting the lexicographic order of
        integer combinations): see BaseMultiIndexCodesEngine documentation.

        Parameters
        ----------
        codes : 1- or 2-dimensional array of dtype uint64
            Combinations of integers (one per row)

        Returns
        -------
        int, or 1-dimensional array of dtype object
            Integer(s) representing one combination (each).
        objectrK   rL   )astyperN   rO   rP   rQ   rR   rS   rV   rV   rW   rX      s   
z$MultiIndexPyIntEngine._codes_to_intsN)rY   rZ   r[   r\   r]   ObjectEnginer_   rX   rV   rV   rV   rW   r`      s    r`   methr   returnc                   s   t   fdd}tt|S )z
    A decorator to allow either `name` or `names` keyword but not both.

    This makes it easier to share code with base class.
    c                   sD   d|v rd|v rt dd|v r|d|d<  | g|R i |S )Nnamenamesz*Can only provide one of `names` and `name`)	TypeErrorpop)self_or_clsargskwargsrd   rV   rW   new_meth   s
   znames_compat.<locals>.new_meth)r   r   r   )rd   rn   rV   rm   rW   names_compat   s   
ro   c                      s  e Zd ZU dZeje B ZdZg Zde	d< e
 Ze
 ZdgZde	d< 									
dadbddZdcddZdddeddZedejfdfddZee		dddgdd Zedejfdhd$d%Zedddid(d)Zedjd+d,Zedjd-d.Zed/d0 Zedkd2d3Zdld5d6Zedmd8d9Z dd	d
d	d:dnd>d?Z!e"dd@dgdA	
dodpdBdCZ#edldDdEZ$edqdGdHZ%edIdJ Z&dd	d
d	d:dndKdLZ'e"dd@dgdAdodpdMdNZ(edOdP Z)edrdRdSZ*e+ej,ejfdsdUdVZ,dfdWdXZ-							dtdYdZZ.dudjd[d\Z/dud]d^Z0e+ej1dvdadbZ1edwdddeZ2dxdfdgZ3e+ej4dydzdidjZ4edldkdlZ5dydzdmdnZ6dodp Z7dqdrd{dtduZ8						v		
d|d}ddZ9dmddZ:dd
dd~ddZ;ee;e:ddZ<e+ej=dd
ddddZ=edddZ>dlddZ?edxddZ@edxddZAedddZBe+ejCddddZCeCZDddddZEe+ejFddddZFdydddZGdd ZHe+ejIdu fdd	ZId
ejd	fdddZJdddZKdxddZLdxddZMedlddZNedlddZOdfddZPdfddZQdd ZRdd ZSdddĄZTeUeVd eW 		
	ddddʄZXdd̄ ZYdddτZZeUeVd eW dudddӄZ[dddքZ\ddfdd؄Z]ddfdd܄Z^dfddބZ_dddZ`	
ddddZadddZbdddZcdddZdedxddZedddZfd fddZgd fddZhdddZiejfdd dZjdddejfd fddZkdddd	ZldddZmduddZnddddZoddddZp	ddddZqdd ZrdddZsdddfd d!Ztdd$d%Zudd&d'Zvdf fd(d)Zwdd,d-Zxdfd.d/Zyd0d1 Zzdfd2d3Z{dfd4d5Z|d6d7 Z}e+ej~ddd8d9Z~d:d; Zdd=d>Zdfd?d@Ze+ejduddAdBZe"dd@dgdAdd fdEdFZeZe"dd@gdAdd fdIdJZedKZedLZedMZedNZedOZedPZedQZedRZedSZedTZedUZedVZedWZedXZedYZedZZed[Zed\Zed]Zed^Zed_Zed`Z  ZS (  rF   a  
    A multi-level, or hierarchical, index object for pandas objects.

    Parameters
    ----------
    levels : sequence of arrays
        The unique labels for each level.
    codes : sequence of arrays
        Integers for each level designating which label at each location.
    sortorder : optional int
        Level of sortedness (must be lexicographically sorted by that
        level).
    names : optional sequence of objects
        Names for each of the index levels. (name is accepted for compat).
    copy : bool, default False
        Copy the meta-data.
    verify_integrity : bool, default True
        Check that the levels/codes are consistent and valid.

    Attributes
    ----------
    names
    levels
    codes
    nlevels
    levshape

    Methods
    -------
    from_arrays
    from_tuples
    from_product
    from_frame
    set_levels
    set_codes
    to_frame
    to_flat_index
    sortlevel
    droplevel
    swaplevel
    reorder_levels
    remove_unused_levels
    get_locs

    See Also
    --------
    MultiIndex.from_arrays  : Convert list of arrays to MultiIndex.
    MultiIndex.from_product : Create a MultiIndex from the cartesian product
                              of iterables.
    MultiIndex.from_tuples  : Convert list of tuples to a MultiIndex.
    MultiIndex.from_frame   : Make a MultiIndex from a DataFrame.
    Index : The base pandas Index type.

    Notes
    -----
    See the `user guide
    <https://pandas.pydata.org/pandas-docs/stable/user_guide/advanced.html>`__
    for more.

    Examples
    --------
    A new ``MultiIndex`` is typically constructed using one of the helper
    methods :meth:`MultiIndex.from_arrays`, :meth:`MultiIndex.from_product`
    and :meth:`MultiIndex.from_tuples`. For example (using ``.from_arrays``):

    >>> arrays = [[1, 1, 2, 2], ['red', 'blue', 'red', 'blue']]
    >>> pd.MultiIndex.from_arrays(arrays, names=('number', 'color'))
    MultiIndex([(1,  'red'),
                (1, 'blue'),
                (2,  'red'),
                (2, 'blue')],
               names=['number', 'color'])

    See further examples for how to construct a MultiIndex in the doc strings
    of the mentioned helper methods.
    
multiindexzlist[Hashable | None]_namesrg   
int | None	sortorderNFTverify_integrityboolre   c	                 C  s   |d ur|}|d u s|d u rt dt|t|krtdt|dkr(tdt| }	i |	_|	j||dd |	j||dd d gt| |	_|d urQ|		| |d ur[t
||	_n||	_|rg|	 }
|
|	_|	  |	S )NzMust pass both levels and codesz,Length of levels and codes must be the same.r   z)Must pass non-zero number of levels/codesF)copyvalidate)rh   len
ValueErrorra   __new___cache_set_levels
_set_codesrq   
_set_namesintrs   _verify_integrity_codes_reset_identity)clslevelsrU   rs   rg   dtyperv   rf   rt   result	new_codesrV   rV   rW   rz   .  s.   

zMultiIndex.__new__levellistcodec                 C  s(   t |}t|rt|| d|}|S )a  
        Reassign code values as -1 if their corresponding levels are NaN.

        Parameters
        ----------
        code : list
            Code to reassign.
        level : list
            Level to check for missing values (NaN, NaT, None).

        Returns
        -------
        new code where code value = -1 if it corresponds
        to a level with missing values (NaN, NaT, None).
        )r6   rP   anywhere)rT   r   r   	null_maskrV   rV   rW   _validate_codes]  s   
zMultiIndex._validate_codesrU   list | Noner   c              	     sb  |p j }|p	 j}t|t|krtdt|d }tt||D ]\\}\}}t||kr;tddd |D  t|rY| t|krYtd| d|  dt| d	t|rp| d
k rptd| d|  d|jstdt	| d| q# j
dur j
t j  jkrtd j
 dt j  j  fddt||D }t|}|S )a7  
        Parameters
        ----------
        codes : optional list
            Codes to check for validity. Defaults to current codes.
        levels : optional list
            Levels to check for validity. Defaults to current levels.

        Raises
        ------
        ValueError
            If length of levels and codes don't match, if the codes for any
            level would exceed level bounds, or there are any duplicate levels.

        Returns
        -------
        new codes where code value = -1 if it corresponds to a
        NaN level.
        zTLength of levels and codes must match. NOTE: this index is in an inconsistent state.r   zUnequal code lengths: c                 S     g | ]}t |qS rV   rx   ).0code_rV   rV   rW   
<listcomp>      z0MultiIndex._verify_integrity.<locals>.<listcomp>z	On level z, code max (z) >= length of level (z/). NOTE: this index is in an inconsistent stater   z, code value (z) < -1zLevel values must be unique: z
 on level NzQValue for sortorder must be inferior or equal to actual lexsort_depth: sortorder z with lexsort_depth c                   s   g | ]
\}}  ||qS rV   )r   )r   r   r   rT   rV   rW   r     s    )rU   r   rx   ry   	enumeratezipmaxmin	is_uniquer   rs   _lexsort_depthnlevelsr=   )rT   rU   r   codes_lengthir   level_codesr   rV   r   rW   r   u  sN   



zMultiIndex._verify_integrityc           	      C  s   d}t |s
t|t|rt|}|D ]
}t |st|qtdt|D ]}t|| t||d  kr:tdq&t|\}}|tj	u rMdd |D }| ||||ddS )a  
        Convert arrays to MultiIndex.

        Parameters
        ----------
        arrays : list / sequence of array-likes
            Each array-like gives one level's value for each data point.
            len(arrays) is the number of levels.
        sortorder : int or None
            Level of sortedness (must be lexicographically sorted by that
            level).
        names : list / sequence of str, optional
            Names for the levels in the index.

        Returns
        -------
        MultiIndex

        See Also
        --------
        MultiIndex.from_tuples : Convert list of tuples to MultiIndex.
        MultiIndex.from_product : Make a MultiIndex from cartesian product
                                  of iterables.
        MultiIndex.from_frame : Make a MultiIndex from a DataFrame.

        Examples
        --------
        >>> arrays = [[1, 1, 2, 2], ['red', 'blue', 'red', 'blue']]
        >>> pd.MultiIndex.from_arrays(arrays, names=('number', 'color'))
        MultiIndex([(1,  'red'),
                    (1, 'blue'),
                    (2,  'red'),
                    (2, 'blue')],
                   names=['number', 'color'])
        z/Input must be a list / sequence of array-likes.rK   zall arrays must be same lengthc                 S     g | ]}t |d dqS rf   Ngetattr)r   arrrV   rV   rW   r         z*MultiIndex.from_arrays.<locals>.<listcomp>Fr   rU   rs   rg   rt   )
r-   rh   r,   r   rangerx   ry   r8   r   
no_default)	r   arraysrs   rg   	error_msgarrayr   rU   r   rV   rV   rW   from_arrays  s.   %
zMultiIndex.from_arraystuplesIterable[tuple[Hashable, ...]]$Sequence[Hashable] | Hashable | Nonec                 C  s6  t |stdt|rt|}ttttdf  |}t|rFt	dd |D rFt
t|g}ttj|t
ddg}| ||||ddS t|d	kr\|d
u rTtdg gt| }n7t|t
jtfrxt|trot
|j}tt|j}nt|trtt|j}nt| }tttt  |}| j|||dS )a}  
        Convert list of tuples to MultiIndex.

        Parameters
        ----------
        tuples : list / sequence of tuple-likes
            Each tuple is the index of one row/column.
        sortorder : int or None
            Level of sortedness (must be lexicographically sorted by that
            level).
        names : list / sequence of str, optional
            Names for the levels in the index.

        Returns
        -------
        MultiIndex

        See Also
        --------
        MultiIndex.from_arrays : Convert list of arrays to MultiIndex.
        MultiIndex.from_product : Make a MultiIndex from cartesian product
                                  of iterables.
        MultiIndex.from_frame : Make a MultiIndex from a DataFrame.

        Examples
        --------
        >>> tuples = [(1, 'red'), (1, 'blue'),
        ...           (2, 'red'), (2, 'blue')]
        >>> pd.MultiIndex.from_tuples(tuples, names=('number', 'color'))
        MultiIndex([(1,  'red'),
                    (1, 'blue'),
                    (2,  'red'),
                    (2, 'blue')],
                   names=['number', 'color'])
        z/Input must be a list / sequence of tuple-likes..c                 s  s     | ]}t |to| V  qd S N)
isinstancetuple)r   erV   rV   rW   	<genexpr>'  s    z)MultiIndex.from_tuples.<locals>.<genexpr>ra   r   Fr   r   Nz-Cannot infer number of levels from empty listrs   rg   )r-   rh   r,   r   r   r	   r   r
   rx   allrP   zerosr9   comasarray_tuplesafer   r   ndarrayasarray_valuesr   tuples_to_object_arrayTto_object_array_tuplesr   r   r   r   )r   r   rs   rg   rU   r   r   arrsrV   rV   rW   from_tuples  s8   +	

zMultiIndex.from_tuples	iterablesSequence[Iterable[Hashable]]"Sequence[Hashable] | lib.NoDefaultc                 C  sh   ddl m} t|stdt|rt|}t|\}}|tju r(dd |D }||}| ||||dS )a  
        Make a MultiIndex from the cartesian product of multiple iterables.

        Parameters
        ----------
        iterables : list / sequence of iterables
            Each iterable has unique labels for each level of the index.
        sortorder : int or None
            Level of sortedness (must be lexicographically sorted by that
            level).
        names : list / sequence of str, optional
            Names for the levels in the index.

            .. versionchanged:: 1.0.0

               If not explicitly provided, names will be inferred from the
               elements of iterables if an element has a name attribute

        Returns
        -------
        MultiIndex

        See Also
        --------
        MultiIndex.from_arrays : Convert list of arrays to MultiIndex.
        MultiIndex.from_tuples : Convert list of tuples to MultiIndex.
        MultiIndex.from_frame : Make a MultiIndex from a DataFrame.

        Examples
        --------
        >>> numbers = [0, 1, 2]
        >>> colors = ['green', 'purple']
        >>> pd.MultiIndex.from_product([numbers, colors],
        ...                            names=['number', 'color'])
        MultiIndex([(0,  'green'),
                    (0, 'purple'),
                    (1,  'green'),
                    (1, 'purple'),
                    (2,  'green'),
                    (2, 'purple')],
                   names=['number', 'color'])
        r   )cartesian_productz-Input must be a list / sequence of iterables.c                 S  r   r   r   )r   itrV   rV   rW   r     r   z+MultiIndex.from_product.<locals>.<listcomp>r   )	pandas.core.reshape.utilr   r-   rh   r,   r   r8   r   r   )r   r   rs   rg   r   rU   r   rV   rV   rW   from_productF  s   1
zMultiIndex.from_productdfrD   c                 C  sB   t |ts	tdt|  \}}|du r|n|}| j|||dS )aK  
        Make a MultiIndex from a DataFrame.

        Parameters
        ----------
        df : DataFrame
            DataFrame to be converted to MultiIndex.
        sortorder : int, optional
            Level of sortedness (must be lexicographically sorted by that
            level).
        names : list-like, optional
            If no names are provided, use the column names, or tuple of column
            names if the columns is a MultiIndex. If a sequence, overwrite
            names with the given sequence.

        Returns
        -------
        MultiIndex
            The MultiIndex representation of the given DataFrame.

        See Also
        --------
        MultiIndex.from_arrays : Convert list of arrays to MultiIndex.
        MultiIndex.from_tuples : Convert list of tuples to MultiIndex.
        MultiIndex.from_product : Make a MultiIndex from cartesian product
                                  of iterables.

        Examples
        --------
        >>> df = pd.DataFrame([['HI', 'Temp'], ['HI', 'Precip'],
        ...                    ['NJ', 'Temp'], ['NJ', 'Precip']],
        ...                   columns=['a', 'b'])
        >>> df
              a       b
        0    HI    Temp
        1    HI  Precip
        2    NJ    Temp
        3    NJ  Precip

        >>> pd.MultiIndex.from_frame(df)
        MultiIndex([('HI',   'Temp'),
                    ('HI', 'Precip'),
                    ('NJ',   'Temp'),
                    ('NJ', 'Precip')],
                   names=['a', 'b'])

        Using explicit names, instead of the column names

        >>> pd.MultiIndex.from_frame(df, names=['state', 'observation'])
        MultiIndex([('HI',   'Temp'),
                    ('HI', 'Precip'),
                    ('NJ',   'Temp'),
                    ('NJ', 'Precip')],
                   names=['state', 'observation'])
        zInput must be a DataFrameNr   )r   r2   rh   r   itemsr   )r   r   rs   rg   column_namescolumnsrV   rV   rW   
from_frame  s
   
9zMultiIndex.from_frame
np.ndarrayc                 C  s   g }t | jD ]V}| j| }| j| }|}t|jr$td|}|j }t	|t
}|r4tj|||jd}t	|jtsAt	|t
tfrF|t}tj|dd}|sXtj|||jd}|| qt|}|S )NrC   
fill_valueFrv   )r   r   r   rU   r(   r   r   _data_internal_get_valuesr   r3   r   take_nd	_na_valuer1   r4   rb   ra   rP   r   appendr   fast_zip)rT   valuesr   r   rU   valsis_dtir   rV   rV   rW   r     s*   







zMultiIndex._valuesc                 C     | j S r   r   r   rV   rV   rW   r        zMultiIndex.valuesc                 C     t d)z
        Raises a ValueError for `MultiIndex` because there's no single
        array backing a MultiIndex.

        Raises
        ------
        ValueError
        zcMultiIndex has no single backing array. Use 'MultiIndex.to_numpy()' to get a NumPy array of tuples.)ry   r   rV   rV   rW   r     s   
zMultiIndex.arrayrE   c                 C  s>   ddl m} tdd | jD }|dd | jD t|dS )zN
        Return the dtypes as a Series for the underlying MultiIndex.
        r   )rE   c                 S     g | ]}|j qS rV   rf   r   r   rV   rV   rW   r         z%MultiIndex.dtypes.<locals>.<listcomp>c                 S  r   rV   r   r   rV   rV   rW   r     r   )r   )pandasrE   r   fill_missing_namesr   r9   )rT   rE   rg   rV   rV   rW   dtypes  s   zMultiIndex.dtypesr   c                 C  s   t | jd S Nr   )rx   rU   r   rV   rV   rW   __len__	  s   zMultiIndex.__len__r=   c                 C  s0   dd t | j| jD }|D ]}d|_qt|S )Nc                 S  s   g | ]
\}}|j |d qS )r   )_rename)r   xrf   rV   rV   rW   r     s    z%MultiIndex.levels.<locals>.<listcomp>T)r   _levelsrq   _no_setting_namer=   )rT   r   r   rV   rV   rW   r     s   zMultiIndex.levels)r   rv   rw   rt   rv   rw   Nonec                  s  |r+t |dkrtd|d u rt |jkrtd|d ur+t |t |kr+td|d u r;t fdd|D }n&fdd|D }tj}t||D ]\}	}
t|
 d	 ||	< qNt|}|rlj	|d
}|_
j}|_t|r{|   d S )Nr   z#Must set non-zero number of levels.z-Length of levels must match number of levels.z,Length of levels must match length of level.c                 3  s     | ]}t | d  V  qdS r   N)r;   _viewr   levr   rV   rW   r   /  s    
z)MultiIndex._set_levels.<locals>.<genexpr>c                      g | ]}  |qS rV   _get_level_numberr   r   rV   rW   r   3      z*MultiIndex._set_levels.<locals>.<listcomp>r   r   )rx   ry   r   r=   r   r   r   r;   r   r   r   rg   r   r~   _reset_cache)rT   r   r   rv   rw   rt   
new_levelslevel_numbersnew_levels_listlev_numr   r   rg   rV   rv   rT   rW   r|     s0   


zMultiIndex._set_levelsrT   )versionallowed_argsc                 C  s   |durt jdtt d nd}t|rt|tst|}t||d\}}|r*| }n| 	 }|
  |j||d|d |s?|S dS )a
  
        Set new levels on MultiIndex. Defaults to returning new index.

        Parameters
        ----------
        levels : sequence or list of sequence
            New level(s) to apply.
        level : int, level name, or sequence of int/level names (default None)
            Level(s) to set (None for all levels).
        inplace : bool
            If True, mutates in place.

            .. deprecated:: 1.2.0
        verify_integrity : bool, default True
            If True, checks that levels and codes are compatible.

        Returns
        -------
        new index (of same type and class...etc) or None
            The same type as the caller or None if ``inplace=True``.

        Examples
        --------
        >>> idx = pd.MultiIndex.from_tuples(
        ...     [
        ...         (1, "one"),
        ...         (1, "two"),
        ...         (2, "one"),
        ...         (2, "two"),
        ...         (3, "one"),
        ...         (3, "two")
        ...     ],
        ...     names=["foo", "bar"]
        ... )
        >>> idx
        MultiIndex([(1, 'one'),
            (1, 'two'),
            (2, 'one'),
            (2, 'two'),
            (3, 'one'),
            (3, 'two')],
           names=['foo', 'bar'])

        >>> idx.set_levels([['a', 'b', 'c'], [1, 2]])
        MultiIndex([('a', 1),
                    ('a', 2),
                    ('b', 1),
                    ('b', 2),
                    ('c', 1),
                    ('c', 2)],
                   names=['foo', 'bar'])
        >>> idx.set_levels(['a', 'b', 'c'], level=0)
        MultiIndex([('a', 'one'),
                    ('a', 'two'),
                    ('b', 'one'),
                    ('b', 'two'),
                    ('c', 'one'),
                    ('c', 'two')],
                   names=['foo', 'bar'])
        >>> idx.set_levels(['a', 'b'], level='bar')
        MultiIndex([(1, 'a'),
                    (1, 'b'),
                    (2, 'a'),
                    (2, 'b'),
                    (3, 'a'),
                    (3, 'b')],
                   names=['foo', 'bar'])

        If any of the levels passed to ``set_levels()`` exceeds the
        existing length, all of the values from that argument will
        be stored in the MultiIndex levels, though the values will
        be truncated in the MultiIndex output.

        >>> idx.set_levels([['a', 'b', 'c'], [1, 2, 3, 4]], level=[0, 1])
        MultiIndex([('a', 1),
            ('a', 2),
            ('b', 1),
            ('b', 2),
            ('c', 1),
            ('c', 2)],
           names=['foo', 'bar'])
        >>> idx.set_levels([['a', 'b', 'c'], [1, 2, 3, 4]], level=[0, 1]).levels
        FrozenList([['a', 'b', 'c'], [1, 2, 3, 4]])
        N>inplace is deprecated and will be removed in a future version.
stacklevelFLevelsT)r   rw   rt   )warningswarnFutureWarningr$   r-   r   r9   r   _require_listliker   r   r|   )rT   r   r   inplacert   idxrV   rV   rW   
set_levelsD  s(   XzMultiIndex.set_levelsc                 C  
   t | jS )a  
        Integer number of levels in this MultiIndex.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([['a'], ['b'], ['c']])
        >>> mi
        MultiIndex([('a', 'b', 'c')],
                   )
        >>> mi.nlevels
        3
        )rx   r   r   rV   rV   rW   r     s   
zMultiIndex.nlevelsr   c                 C  s   t dd | jD S )a  
        A tuple with the length of each level.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([['a'], ['b'], ['c']])
        >>> mi
        MultiIndex([('a', 'b', 'c')],
                   )
        >>> mi.levshape
        (1, 1, 1)
        c                 s      | ]}t |V  qd S r   r   r   r   rV   rV   rW   r         z&MultiIndex.levshape.<locals>.<genexpr>)r   r   r   rV   rV   rW   levshape  s   zMultiIndex.levshapec                 C  r   r   )r   r   rV   rV   rW   rU     r   zMultiIndex.codesc                  s   |r!|d u rt |jkrtd|d ur!t |t |kr!td|d u r5t fddtj|D }n*fdd|D }tj}t||D ]\}	}
j|	 }t	|
| d||	< qHt|}|rgj
|d}|_  d S )	Nz+Length of codes must match number of levelsz,Length of codes must match length of levels.c                 3  s&    | ]\}}t || d  V  qdS r   )_coerce_indexer_frozenview)r   r   r   r   rV   rW   r     s
    
z(MultiIndex._set_codes.<locals>.<genexpr>c                   r   rV   r   r   r   rV   rW   r     r   z)MultiIndex._set_codes.<locals>.<listcomp>r   rU   )rx   r   ry   r=   r   r   r   r   r   r  r   r   )rT   rU   r   rv   rw   rt   r   r   new_codes_listr   r   r   rV   r   rW   r}     s*   	



zMultiIndex._set_codesc                 C  sf   |durt jdtt d nd}t||d\}}|r| }n|  }|  |j|||d |s1|S dS )a  
        Set new codes on MultiIndex. Defaults to returning new index.

        Parameters
        ----------
        codes : sequence or list of sequence
            New codes to apply.
        level : int, level name, or sequence of int/level names (default None)
            Level(s) to set (None for all levels).
        inplace : bool
            If True, mutates in place.

            .. deprecated:: 1.2.0
        verify_integrity : bool, default True
            If True, checks that levels and codes are compatible.

        Returns
        -------
        new index (of same type and class...etc) or None
            The same type as the caller or None if ``inplace=True``.

        Examples
        --------
        >>> idx = pd.MultiIndex.from_tuples(
        ...     [(1, "one"), (1, "two"), (2, "one"), (2, "two")], names=["foo", "bar"]
        ... )
        >>> idx
        MultiIndex([(1, 'one'),
            (1, 'two'),
            (2, 'one'),
            (2, 'two')],
           names=['foo', 'bar'])

        >>> idx.set_codes([[1, 0, 1, 0], [0, 0, 1, 1]])
        MultiIndex([(2, 'one'),
                    (1, 'one'),
                    (2, 'two'),
                    (1, 'two')],
                   names=['foo', 'bar'])
        >>> idx.set_codes([1, 0, 1, 0], level=0)
        MultiIndex([(2, 'one'),
                    (1, 'two'),
                    (2, 'one'),
                    (1, 'two')],
                   names=['foo', 'bar'])
        >>> idx.set_codes([0, 0, 1, 1], level='bar')
        MultiIndex([(1, 'one'),
                    (1, 'one'),
                    (2, 'two'),
                    (2, 'two')],
                   names=['foo', 'bar'])
        >>> idx.set_codes([[1, 0, 1, 0], [0, 0, 1, 1]], level=[0, 1])
        MultiIndex([(2, 'one'),
                    (1, 'one'),
                    (2, 'two'),
                    (1, 'two')],
                   names=['foo', 'bar'])
        Nr  r  FCodes)r   rt   )r  r  r  r$   r  r   r   r}   )rT   rU   r   r	  rt   r
  rV   rV   rW   	set_codes  s    <zMultiIndex.set_codesc                 C  s   t t dd | jD }t |d d d d d d }t |dd  dggd}|d dkr:t| j| j|S t	| j| j|S )Nc                 S  s   g | ]}t |d  qS )rK   r   r   rV   rV   rW   r   X  r   z&MultiIndex._engine.<locals>.<listcomp>r   rK   r   uint64@   )
rP   ceillog2r   cumsumconcatenaterb   r`   rU   rJ   )rT   sizeslev_bitsrN   rV   rV   rW   _engineT  s   zMultiIndex._engineCallable[..., MultiIndex]c                 C  s
   t | jS r   )typer   r   rV   rV   rW   _constructorl     
zMultiIndex._constructorr   c                 C  s(   |t jur|n| j}t| j|d |dS )Nr   )r   r   rg   r!  r   )rT   r   rf   rg   rV   rV   rW   _shallow_copyp  s   zMultiIndex._shallow_copyc                 C  s<   t | | j| j| j| jdd}| j |_|jdd  |S )NFr   r   )r!  r   rU   rs   rg   r{   rv   ri   )rT   r   rV   rV   rW   r   v  s   zMultiIndex._viewc           
      C  s  | j |||d}| }|durtjdtt d d}|dur)tjdtt d d}|rCddlm} |du r:|| j}|du rC|| j}|durI|n| j}|durR|n| j}t	| ||| j
|dd	}	| j |	_|	jd
d |rt| j|	_|rtjdtt d |	|}	|	S )ae  
        Make a copy of this object. Names, dtype, levels and codes can be
        passed and will be set on new copy.

        Parameters
        ----------
        names : sequence, optional
        dtype : numpy dtype or pandas type, optional

            .. deprecated:: 1.2.0
        levels : sequence, optional

            .. deprecated:: 1.2.0
        codes : sequence, optional

            .. deprecated:: 1.2.0
        deep : bool, default False
        name : Label
            Kept for compatibility with 1-dimensional Index. Should not be used.

        Returns
        -------
        MultiIndex

        Notes
        -----
        In most cases, there should be no functional difference from using
        ``deep``, but if ``deep`` is passed it will attempt to deepcopy.
        This could be potentially expensive on large MultiIndex objects.
        )rf   rg   deepNzjparameter levels is deprecated and will be removed in a future version. Use the set_levels method instead.r  Fzhparameter codes is deprecated and will be removed in a future version. Use the set_codes method instead.r   )deepcopyr   r   zeparameter dtype is deprecated and will be removed in a future version. Use the astype method instead.)_validate_namesr  r  r  r$   rv   r&  r   rU   r!  rs   r{   ri   _idrb   )
rT   rg   r   r   rU   r%  rf   keep_idr&  	new_indexrV   rV   rW   rv     sV   '


zMultiIndex.copyc                 C  r   )z%the array interface, return my values)r   rT   r   rV   rV   rW   	__array__  r   zMultiIndex.__array__c                 C  s   |   }| j|_|S )z0this is defined as a copy with the same identity)rv   r(  )rT   r   r   rV   rV   rW   r    s   zMultiIndex.viewkeyr   c              
   C  s4   t | z| | W dS  tttfy   Y dS w )NTF)hashget_locLookupErrorrh   ry   rT   r-  rV   rV   rW   __contains__  s   
zMultiIndex.__contains__np.dtypec                 C  s
   t dS )NO)rP   r   r   rV   rV   rW   r     r#  zMultiIndex.dtypec                   s    dd  t  fdd| jD S )z5return a boolean if we need a qualified .info displayc                 S  s   d| v pd| v pd| v S )NmixedstringunicoderV   r   rV   rV   rW   f  s   z0MultiIndex._is_memory_usage_qualified.<locals>.fc                 3  s    | ]} |V  qd S r   rV   r   r9  rV   rW   r     r  z8MultiIndex._is_memory_usage_qualified.<locals>.<genexpr>)r   _inferred_type_levelsr   rV   r:  rW   _is_memory_usage_qualified  s   z%MultiIndex._is_memory_usage_qualifiedr%  c                 C  s
   |  |S r   _nbytes)rT   r%  rV   rV   rW   memory_usage  s   
zMultiIndex.memory_usagec                 C  s
   |  dS )z1return the number of bytes in the underlying dataFr=  r   rV   rV   rW   nbytes  s   
zMultiIndex.nbytesc                   sj   dt  fdd| jD }t dd | jD }t fdd| jD }|| | }|| jj d7 }|S )z
        return the number of bytes in the underlying data
        deeply introspect the level data if deep=True

        include the engine hashtable

        *this is in internal routine*

           c                 3  s    | ]	}|j  d V  qdS )r%  N)r?  r   r   rB  rV   rW   r         z%MultiIndex._nbytes.<locals>.<genexpr>c                 s      | ]}|j V  qd S r   )r@  rC  rV   rV   rW   r         c                 3  s    | ]}t | V  qd S r   r   rC  )objsizerV   rW   r         rB  )sumr   rU   rg   r  sizeof)rT   r%  level_nbyteslabel_nbytesnames_nbytesr   rV   )r%  rG  rW   r>  
  s   zMultiIndex._nbytesc                 C  s(   dd | j D }tdd t||D S )zW
        Formats each item in tup according to its level's formatter function.
        c                 S  r   rV   )_formatter_funcr   rV   rV   rW   r   '  r   z.MultiIndex._formatter_func.<locals>.<listcomp>c                 s  s    | ]	\}}||V  qd S r   rV   )r   funcvalrV   rV   rW   r   (  rD  z-MultiIndex._formatter_func.<locals>.<genexpr>)r   r   r   )rT   tupformatter_funcsrV   rV   rW   rN  #  s   zMultiIndex._formatter_funcnan)na_repnpt.NDArray[np.object_]c                K  s   g }g }t | j| jD ]=\}}|jdd|i|}|dk}| r>t|}	|t}t	||}|j
jr6J | }|	||< |	| |	| qt|dkr\t|d |d  S t||| j| jdd}
|
jS )NrT  r   rK   r   Fr   rU   rg   rs   rt   rV   )r   r   rU   _format_native_typesr   rx   rb   strrP   r   flags	writeablerv   r9   takerF   rg   rs   r   )rT   rT  rl   r   r   r   r   
level_strsmask	nan_indexmirV   rV   rW   rW  *  s0   

zMultiIndex._format_native_types   rf   bool | None	formatterCallable | NonerT  
str | Nonespaceadjoinc                   s  |d ur|}t | dkrg S g }t| j| jD ]I\}	}
|d ur!|nt|	j t |	dkrM|	|
j|d}|
dk}| rLt	j
|td} ||< | }n fddt|	j|
D }|| qg }t|| jD ]&\}	}g }|r||d ur}t|ddnd	 |t	j
|	td || qi|d u rtd
}|rd	}t|ts|tju sJ |dtjfv r|}t|t||d}|rddlm} | }|j|g|R  dS |S )Nr   )rb  r   r   c                   s$   g | ]}t t|r n|d dqS )	
escape_chars)rB   r6   r  narV   rW   r   o  s    z%MultiIndex.format.<locals>.<listcomp>rg  rk   zdisplay.multi_sparseF)startsentinel)get_adjustmentrj  )rx   r   r   rU   _get_na_repr   r[  formatr   rP   r   ra   tolistr   r   r   r   rg   rB   extendr   r   ru   r   r   sparsify_labelsr   pandas.io.formats.formatrr  rf  split)rT   rf   rb  rT  rg   re  sparsifyrf  stringified_levelsr   r   	formattedr]  result_levelslev_namer   rq  rr  adjrV   rm  rW   rt  N  sZ   


zMultiIndex.formatc                 C  r  r   )r=   rq   r   rV   rV   rW   
_get_names  s   
zMultiIndex._get_names)r   rw   c                  s   |durt |stdt|}|r1|dur"t|t|kr"td|du r1t| jkr1td|du r;t j}n	 fdd|D }t||D ]\}}|dur_t|s_tt	 j
 d| j|< qI   dS )a  
        Set new names on index. Each name has to be a hashable type.

        Parameters
        ----------
        values : str or sequence
            name(s) to set
        level : int, level name, or sequence of int/level names (default None)
            If the index is a MultiIndex (hierarchical), level(s) to set (None
            for all levels).  Otherwise level must be None
        validate : bool, default True
            validate that the names match level lengths

        Raises
        ------
        TypeError if each name is not hashable.

        Notes
        -----
        sets names on levels. WARNING: mutates!

        Note that you generally want to set this *after* changing levels, so
        that it only acts on copies
        Nz*Names should be list-like for a MultiIndexz+Length of names must match length of level.z:Length of names must match number of levels in MultiIndex.c                   r   rV   r   r   r   rV   rW   r     r   z)MultiIndex._set_names.<locals>.<listcomp>z.name must be a hashable type)r-   ry   r   rx   r   r   r   r*   rh   r!  rY   rq   r   )rT   rg   r   rw   r   rf   rV   r   rW   r~     s*   zMultiIndex._set_namesam  
        Names of levels in MultiIndex.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays(
        ... [[1, 2], [3, 4], [5, 6]], names=['x', 'y', 'z'])
        >>> mi
        MultiIndex([(1, 3, 5),
                    (2, 4, 6)],
                   names=['x', 'y', 'z'])
        >>> mi.names
        FrozenList(['x', 'y', 'z'])
        )fsetfgetr#   )r   dropnar  @tuple[Index, npt.NDArray[np.signedinteger] | None, Index | None]c          
      C  s   |d ur| j | }| j| |}||}|d d fS | |}tj|d|d\}}	t|	ts1J | j| j	r?|	j|dd}n|	|}|||	fS )NT)sortuse_na_sentinelr   )
rU   r   r[  mapget_level_valuesr   	factorizer   r9   _can_hold_na)
rT   mapperr   r  indexerlevel_valuesgrouperr   rU   uniquesrV   rV   rW   _get_grouper_for_level  s   





z!MultiIndex._get_grouper_for_levelrX  c                 C  s   dS )Nr5  rV   r   rV   rV   rW   inferred_type  s   zMultiIndex.inferred_typec              
   C  s   | j |}|dkrt|std| dz	| j |}W |S  tyy } zNt|s4td| d||dk rT|| j7 }|dk rS|| j }td| j d| d	|n|| jkrgtd| j d
|d  |W Y d }~|S W Y d }~|S d }~ww )NrK   z	The name z* occurs multiple times, use a level numberzLevel z
 not foundr   z Too many levels: Index has only z	 levels, z is not a valid level numberz levels, not )rg   countr+   ry   r   KeyErrorr   
IndexError)rT   r   r  err
orig_levelrV   rV   rW   r     sJ   







zMultiIndex._get_level_numberc                   s   t dd  jD rdS tdd  jD r!tdd  jD S  fddttt jD }zt	
|}t|jW S  tyK   t jj Y S w )zI
        Return a boolean if the values are equal or increasing.
        c                 s      | ]}d |v V  qdS r   NrV   r   r   rV   rV   rW   r   ,  r  z5MultiIndex.is_monotonic_increasing.<locals>.<genexpr>Fc                 s  rE  r   is_monotonic_increasingr   rV   rV   rW   r   /  rF  c                 S  s   g | ]	}|j d ddqS )int64Fr   )rb   r  rV   rV   rW   r   2  s    z6MultiIndex.is_monotonic_increasing.<locals>.<listcomp>c                   s   g | ]}  |jqS rV   )_get_level_valuesr   rC  r   rV   rW   r   6  s    )r   rU   r   r   libalgosis_lexsortedreversedr   rx   rP   lexsortr9   r  rh   r   )rT   r   
sort_orderrV   r   rW   r  '  s   

z"MultiIndex.is_monotonic_increasingc                 C  s   | ddd j S )zI
        Return a boolean if the values are equal or decreasing.
        Nr   r  r   rV   rV   rW   is_monotonic_decreasingG  s   z"MultiIndex.is_monotonic_decreasing	list[str]c                 C  s   dd | j D S )z7return a list of the inferred types, one for each levelc                 S  r   rV   )r  rC  rV   rV   rW   r   R  r   z4MultiIndex._inferred_type_levels.<locals>.<listcomp>r   r   rV   rV   rW   r;  O  s   z MultiIndex._inferred_type_levelsfirstnpt.NDArray[np.bool_]c                 C  s0   t dd | jD }t| j|ddd}t||S )Nc                 s  r  r   r   r   rV   rV   rW   r   V  r  z(MultiIndex.duplicated.<locals>.<genexpr>F)r  xnull)r   r   r?   rU   r   )rT   keepshapeidsrV   rV   rW   r   T  s   
zMultiIndex.duplicatedc                 C  r   )z:
        fillna is not implemented for MultiIndex
        z"isna is not defined for MultiIndex)NotImplementedError)rT   valuedowncastrV   rV   rW   fillna_  s   zMultiIndex.fillnar   howc                   sn   dd | j D }|dkrtj|dd n|dkr tj|dd ntd|  fdd| j D }| j|d	S )
Nc                 S  s   g | ]}|d kqS )r   rV   r   r   rV   rV   rW   r   g  r   z%MultiIndex.dropna.<locals>.<listcomp>r   r   rL   r   zinvalid how option: c                   s   g | ]}|   qS rV   rV   r  r  rV   rW   r   o  r   r  )rU   rP   r   r   ry   r  )rT   r  nansr   rV   r  rW   r  e  s   zMultiIndex.dropnauniquer9   c                 C  sN   | j | }| j| }| j| }|rt|}tj|j||jd}|j||dS )aP  
        Return vector of label values for requested level,
        equal to the length of the index

        **this is an internal method**

        Parameters
        ----------
        level : int
        unique : bool, default False
            if True, drop duplicated values

        Returns
        -------
        Index
        r   r   )	r   rU   rq   r   r  r   r   r   r$  )rT   r   r  r   r   rf   filledrV   rV   rW   r  r  s   



zMultiIndex._get_level_valuesc                 C  s   |  |}| |}|S )a9  
        Return vector of label values for requested level.

        Length of returned vector is equal to the length of the index.

        Parameters
        ----------
        level : int or str
            ``level`` is either the integer position of the level in the
            MultiIndex, or the name of the level.

        Returns
        -------
        values : Index
            Values is a level of this MultiIndex converted to
            a single :class:`Index` (or subclass thereof).

        Notes
        -----
        If the level contains missing values, the result may be casted to
        ``float`` with missing values specified as ``NaN``. This is because
        the level is converted to a regular ``Index``.

        Examples
        --------
        Create a MultiIndex:

        >>> mi = pd.MultiIndex.from_arrays((list('abc'), list('def')))
        >>> mi.names = ['level_1', 'level_2']

        Get level values by supplying level as either integer or name:

        >>> mi.get_level_values(0)
        Index(['a', 'b', 'c'], dtype='object', name='level_1')
        >>> mi.get_level_values('level_2')
        Index(['d', 'e', 'f'], dtype='object', name='level_2')

        If a level contains missing values, the return type of the level
        maybe casted to ``float``.

        >>> pd.MultiIndex.from_arrays([[1, None, 2], [3, 4, 5]]).dtypes
        level_0    int64
        level_1    int64
        dtype: object
        >>> pd.MultiIndex.from_arrays([[1, None, 2], [3, 4, 5]]).get_level_values(0)
        Float64Index([1.0, nan, 2.0], dtype='float64')
        )r   r  )rT   r   r   rV   rV   rW   r    s   
0
zMultiIndex.get_level_valuesc                   s*   |d u r	t   S | |}| j|ddS )NT)r   r  )superr  r   r  )rT   r   	__class__rV   rW   r    s   

zMultiIndex.uniquer   allow_duplicatesc                   s   ddl m} |du rtjdtt d tj}|tjur3t|s#t	dt
|t
 jkr0td|}n  }|sGt
t|t
|krGtd| fd	d
tt
 jD dd}||_|ra |_|S )a[  
        Create a DataFrame with the levels of the MultiIndex as columns.

        Column ordering is determined by the DataFrame constructor with data as
        a dict.

        Parameters
        ----------
        index : bool, default True
            Set the index of the returned DataFrame as the original MultiIndex.

        name : list / sequence of str, optional
            The passed names should substitute index level names.

        allow_duplicates : bool, optional default False
            Allow duplicate column labels to be created.

            .. versionadded:: 1.5.0

        Returns
        -------
        DataFrame : a DataFrame containing the original MultiIndex data.

        See Also
        --------
        DataFrame : Two-dimensional, size-mutable, potentially heterogeneous
            tabular data.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([['a', 'b'], ['c', 'd']])
        >>> mi
        MultiIndex([('a', 'c'),
                    ('b', 'd')],
                   )

        >>> df = mi.to_frame()
        >>> df
             0  1
        a c  a  c
        b d  b  d

        >>> df = mi.to_frame(index=False)
        >>> df
           0  1
        0  a  c
        1  b  d

        >>> df = mi.to_frame(name=['x', 'y'])
        >>> df
             x  y
        a c  a  c
        b d  b  d
        r   )rD   NzExplicitly passing `name=None` currently preserves the Index's name or uses a default name of 0. This behaviour is deprecated, and in the future `None` will be used as the name of the resulting DataFrame column.r  z1'name' must be a list / sequence of column names.z<'name' should have same length as number of levels on index.zBCannot create duplicate column labels if allow_duplicates is Falsec                   s   i | ]}|  |qS rV   r  r   r   rV   rW   
<dictcomp>$  r   z'MultiIndex.to_frame.<locals>.<dictcomp>Fr   )r   rD   r  r  r  r$   r   r   r-   rh   rx   r   ry   _get_level_namessetr   r   r   )rT   r   rf   r  rD   	idx_namesr   rV   r   rW   to_frame  s:   <
zMultiIndex.to_framec                 C  s   t | jddS )a  
        Convert a MultiIndex to an Index of Tuples containing the level values.

        Returns
        -------
        pd.Index
            Index with the MultiIndex data represented in Tuples.

        See Also
        --------
        MultiIndex.from_tuples : Convert flat index back to MultiIndex.

        Notes
        -----
        This method will simply return the caller if called by anything other
        than a MultiIndex.

        Examples
        --------
        >>> index = pd.MultiIndex.from_product(
        ...     [['foo', 'bar'], ['baz', 'qux']],
        ...     names=['a', 'b'])
        >>> index.to_flat_index()
        Index([('foo', 'baz'), ('foo', 'qux'),
               ('bar', 'baz'), ('bar', 'qux')],
              dtype='object')
        F)tupleize_cols)r9   r   r   rV   rV   rW   to_flat_index/  s   zMultiIndex.to_flat_indexc                 C  s   t jdtt d |  S )NzxMultiIndex.is_lexsorted is deprecated as a public function, users should use MultiIndex.is_monotonic_increasing instead.r  )r  r  r  r$   _is_lexsortedr   rV   rV   rW   r  M  s   zMultiIndex.is_lexsortedc                 C  s   | j | jkS )a`  
        Return True if the codes are lexicographically sorted.

        Returns
        -------
        bool

        Examples
        --------
        In the below examples, the first level of the MultiIndex is sorted because
        a<b<c, so there is no need to look at the next level.

        >>> pd.MultiIndex.from_arrays([['a', 'b', 'c'], ['d', 'e', 'f']]).is_lexsorted()
        True
        >>> pd.MultiIndex.from_arrays([['a', 'b', 'c'], ['d', 'f', 'e']]).is_lexsorted()
        True

        In case there is a tie, the lexicographical sorting looks
        at the next level of the MultiIndex.

        >>> pd.MultiIndex.from_arrays([[0, 1, 1], ['a', 'b', 'c']]).is_lexsorted()
        True
        >>> pd.MultiIndex.from_arrays([[0, 1, 1], ['a', 'c', 'b']]).is_lexsorted()
        False
        >>> pd.MultiIndex.from_arrays([['a', 'a', 'b', 'b'],
        ...                            ['aa', 'bb', 'aa', 'bb']]).is_lexsorted()
        True
        >>> pd.MultiIndex.from_arrays([['a', 'a', 'b', 'b'],
        ...                            ['bb', 'aa', 'aa', 'bb']]).is_lexsorted()
        False
        )r   r   r   rV   rV   rW   r  V  s    zMultiIndex._is_lexsortedc                 C  s   t jdtt d | jS )NzyMultiIndex.lexsort_depth is deprecated as a public function, users should use MultiIndex.is_monotonic_increasing instead.r  )r  r  r  r$   r   r   rV   rV   rW   lexsort_depthx  s   zMultiIndex.lexsort_depthc                 C  s   | j dur| j S t| j| jS )z
        Compute and return the lexsort_depth, the number of levels of the
        MultiIndex that are sorted lexically

        Returns
        -------
        int
        N)rs   r   rU   r   r   rV   rV   rW   r     s   

zMultiIndex._lexsort_depthc              	   C  s   |   r	| jr	| S g }g }t| j| jD ]8\}}|jsBz| }W n	 ty*   Y nw ||}t|}t	
|t|}t||}|| || qt||| j| jddS )a  
        This is an *internal* function.

        Create a new MultiIndex from the current to monotonically sorted
        items IN the levels. This does not actually make the entire MultiIndex
        monotonic, JUST the levels.

        The resulting MultiIndex will have the same outward
        appearance, meaning the same .values and ordering. It will also
        be .equals() to the original.

        Returns
        -------
        MultiIndex

        Examples
        --------
        >>> mi = pd.MultiIndex(levels=[['a', 'b'], ['bb', 'aa']],
        ...                    codes=[[0, 0, 1, 1], [0, 1, 0, 1]])
        >>> mi
        MultiIndex([('a', 'bb'),
                    ('a', 'aa'),
                    ('b', 'bb'),
                    ('b', 'aa')],
                   )

        >>> mi.sort_values()
        MultiIndex([('a', 'aa'),
                    ('a', 'bb'),
                    ('b', 'aa'),
                    ('b', 'bb')],
                   )
        F)rg   rs   rt   )r  r  r   r   rU   argsortrh   r[  r'   r   get_reverse_indexerrx   r   r   r   rF   rg   rs   )rT   r   r   r   r   r  rirV   rV   rW   _sort_levels_monotonic  s0   "

z!MultiIndex._sort_levels_monotonicc                 C  sZ  g }g }d}t | j| jD ]\}}tt|d dkd d }tt|o+|d dk}t|t|| kr| 	 rGt|t|krG nLd}t
|}|rgt|dkd }||d dg |d|d g< tt|| }	tt|| |	|< |	| }|||d }|| || q|  }
|r|
  |
j|dd |
j|dd |
S )a  
        Create new MultiIndex from current that removes unused levels.

        Unused level(s) means levels that are not expressed in the
        labels. The resulting MultiIndex will have the same outward
        appearance, meaning the same .values and ordering. It will
        also be .equals() to the original.

        Returns
        -------
        MultiIndex

        Examples
        --------
        >>> mi = pd.MultiIndex.from_product([range(2), list('ab')])
        >>> mi
        MultiIndex([(0, 'a'),
                    (0, 'b'),
                    (1, 'a'),
                    (1, 'b')],
                   )

        >>> mi[2:]
        MultiIndex([(1, 'a'),
                    (1, 'b')],
                   )

        The 0 from the first level is not represented
        and can be removed

        >>> mi2 = mi[2:].remove_unused_levels()
        >>> mi2.levels
        FrozenList([[1], ['a', 'b']])
        FrK   r   r   TN)rw   )r   r   rU   rP   r   bincountr   rx   r6   r   r   r  r   aranger[  r   r  r   r|   r}   )rT   r   r   changedr   r   r  has_nana_idxcode_mappingr   rV   rV   rW   remove_unused_levels  s4   # 

zMultiIndex.remove_unused_levelsc                 C  s6   t | jt | j| jt | jd}tjt| |fdfS )z*Necessary for making this object picklable)r   rU   rs   rg   N)r   r   rU   rs   rg   ibase
_new_Indexr!  )rT   drV   rV   rW   
__reduce__-  s   zMultiIndex.__reduce__c                   s   t  r3tj dd g }t| j| jD ]\}}|  dkr%|tj q|||    qt	|S d }t
 rEtj td | j}nt trX jd u sT jdkrW| j}n
t trbt   fdd| jD }t| j|| j|dd	S )
NT)
warn_floatr   r   r   c                      g | ]}|  qS rV   rV   r  r-  rV   rW   r   Q  r   z*MultiIndex.__getitem__.<locals>.<listcomp>FrV  )r/   r   cast_scalar_indexerr   r   rU   r   rP   rS  r   is_bool_indexerr   ru   rs   r   slicestepr9   rF   rg   )rT   r-  retvalr   r   rs   r   rV   r  rW   __getitem__9  s4   



zMultiIndex.__getitem__slobjr  c                   sL   d} j du s j dkr| j} fdd| jD }t| | j|| j|ddS )zH
        Fastpath for __getitem__ when we know we have a slice.
        Nr   c                   r  rV   rV   r  r  rV   rW   r   c  r   z-MultiIndex._getitem_slice.<locals>.<listcomp>FrV  )r  rs   rU   r!  r   rq   )rT   r  rs   r   rV   r  rW   _getitem_slice[  s   zMultiIndex._getitem_slicer[  r   rM   
allow_fillc                   s   t d| t  | || }d} fdd| jD }|r> dk}| r>g }	|D ]}
|
}|||< |	t| q+|	}t	| j
|| jddS )NrV   r   c                      g | ]}|  qS rV   r[  )r   labindicesrV   rW   r   ~  r   z#MultiIndex.take.<locals>.<listcomp>Fr   rU   rg   rt   )nvvalidate_taker'   _maybe_disallow_fillrU   r   r   rP   r   rF   r   rg   )rT   r  rM   r  r   rl   na_valuetakenr]  masked	new_labellabel_valuesrV   r  rW   r[  m  s"   	zMultiIndex.takec              	     s   t |ttfs
|g}tfdd|D r=g }tjD ]  } fdd|D }||| qtj	|j
dS jftdd |D  }t|}z	tj|j
dW S  ttfyh   t| Y S w )z
        Append a collection of Index options together

        Parameters
        ----------
        other : Index or list/tuple of indices

        Returns
        -------
        appended : Index
        c                 3  s&    | ]}t |to|j jkV  qd S r   )r   rF   r   r   or   rV   rW   r     s    
z$MultiIndex.append.<locals>.<genexpr>c                   r  rV   r  r  )r   rV   rW   r     r   z%MultiIndex.append.<locals>.<listcomp>rg   c                 s  rE  r   r   r   krV   rV   rW   r     rF  )r   r   r   r   r   r   r  r   rF   r   rg   r   rP   r  r   rh   r  r9   _with_infer)rT   otherr   labelappended	to_concat
new_tuplesrV   )r   rT   rW   r     s$   

zMultiIndex.appendnpt.NDArray[np.intp]c                 O  s   | j j|i |S r   )r   r  )rT   rk   rl   rV   rV   rW   r    s   zMultiIndex.argsortrepeatrepeatsc                   s@   t dd|i t  t| j fdd| jD | j| jddS )NrV   rM   c                   s*   g | ]}| tjjtjd d qS )Fr   )r  rP   r   rb   intpr  r  r  rV   rW   r     s    z%MultiIndex.repeat.<locals>.<listcomp>FrV  )r  validate_repeatr'   rF   r   rU   rg   rs   )rT   r  rM   rV   r  rW   r    s   
zMultiIndex.repeatraisec           	   	   C  s4  |dur|  |||S t|tjtfs)ztj|tdd}W n	 ty(   Y nw g }|D ]g}zW| 	|}t|t
r@|| nEt|tr[|jdurM|jnd}|t|j|j| n*t|rz| jdkrntjdtt d | d }|| ndt| }t|W q- ty   |d	kr Y q-w | |S )
a^  
        Make new MultiIndex with passed list of codes deleted

        Parameters
        ----------
        codes : array-like
            Must be a list of tuples when level is not specified
        level : int or level name, default None
        errors : str, default 'raise'

        Returns
        -------
        dropped : MultiIndex
        Nra   r   rK   r   zYdropping on a non-lexsorted multi-index without a level parameter may impact performance.r  zunsupported indexer of type ignore)_drop_from_levelr   rP   r   r9   r   index_labels_to_arrayr   ry   r/  r   r   r  r  rv  r   rp  stopr  r   r  r  r   r$   nonzeror!  AssertionErrorr  delete)	rT   rU   r   errorsindsr   locr  msgrV   rV   rW   drop  sF   





zMultiIndex.dropc           
      C  s   t |}| |}| j| }||}t|}d|t|d|dk@ < |jd | jd kr6d|t|d< ||dk }t	|dkrN|dkrNt
d| dt| j| | }	| |	 S )	NFr   r   Tr  zlabels z not found in level)r   r  r   r   get_indexerr6   rP   equalr  rx   r  r   isinrU   )
rT   rU   r   r  r   r   r   	nan_codes	not_foundr]  rV   rV   rW   r     s   



zMultiIndex._drop_from_levelr  r   c                 C  s   t | j}t | j}t | j}| |}| |}|| || ||< ||< || || ||< ||< || || ||< ||< t|||ddS )a  
        Swap level i with level j.

        Calling this method does not change the ordering of the values.

        Parameters
        ----------
        i : int, str, default -2
            First level of index to be swapped. Can pass level name as string.
            Type of parameters can be mixed.
        j : int, str, default -1
            Second level of index to be swapped. Can pass level name as string.
            Type of parameters can be mixed.

        Returns
        -------
        MultiIndex
            A new MultiIndex.

        See Also
        --------
        Series.swaplevel : Swap levels i and j in a MultiIndex.
        DataFrame.swaplevel : Swap levels i and j in a MultiIndex on a
            particular axis.

        Examples
        --------
        >>> mi = pd.MultiIndex(levels=[['a', 'b'], ['bb', 'aa']],
        ...                    codes=[[0, 0, 1, 1], [0, 1, 0, 1]])
        >>> mi
        MultiIndex([('a', 'bb'),
                    ('a', 'aa'),
                    ('b', 'bb'),
                    ('b', 'aa')],
                   )
        >>> mi.swaplevel(0, 1)
        MultiIndex([('bb', 'a'),
                    ('aa', 'a'),
                    ('bb', 'b'),
                    ('aa', 'b')],
                   )
        Fr  )r   r   rU   rg   r   rF   )rT   r   jr   r   	new_namesrV   rV   rW   	swaplevel	  s   
+



zMultiIndex.swaplevelc                   s    fdd|D }t | jkrtd j dt |  fdd|D } fdd|D } fdd|D }t|||dd	S )
aI  
        Rearrange levels using input order. May not drop or duplicate levels.

        Parameters
        ----------
        order : list of int or list of str
            List representing new level order. Reference level by number
            (position) or by key (label).

        Returns
        -------
        MultiIndex

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([[1, 2], [3, 4]], names=['x', 'y'])
        >>> mi
        MultiIndex([(1, 3),
                    (2, 4)],
                   names=['x', 'y'])

        >>> mi.reorder_levels(order=[1, 0])
        MultiIndex([(3, 1),
                    (4, 2)],
                   names=['y', 'x'])

        >>> mi.reorder_levels(order=['y', 'x'])
        MultiIndex([(3, 1),
                    (4, 2)],
                   names=['y', 'x'])
        c                   r   rV   r   rC  r   rV   rW   r   f	  r   z-MultiIndex.reorder_levels.<locals>.<listcomp>z2Length of order must be same as number of levels (z), got c                      g | ]} j | qS rV   r   rC  r   rV   rW   r   l	  r   c                   r  rV   r  rC  r   rV   rW   r   m	  r   c                   r  rV   r  rC  r   rV   rW   r   n	  r   Fr  )rx   r   r  rF   )rT   orderr   r   r  rV   r   rW   reorder_levelsF	  s    
zMultiIndex.reorder_levelslist[Categorical]c                   s   dd   fdd| j D S )a
  
        we are categorizing our codes by using the
        available categories (all, not just observed)
        excluding any missing ones (-1); this is in preparation
        for sorting, where we need to disambiguate that -1 is not
        a valid valid
        c                 S  s*   t jt| rt |  d nd| jdS )NrK   r   r   )rP   r  rx   r   r   r   )r   rV   rV   rW   cats}	  s   z/MultiIndex._get_codes_for_sorting.<locals>.catsc                   s    g | ]}t j| |d dqS )T)ordered)r7   
from_codesr  r  rV   rW   r   	  s    z5MultiIndex._get_codes_for_sorting.<locals>.<listcomp>r  r   rV   r  rW   _get_codes_for_sortingt	  s   	
z!MultiIndex._get_codes_for_sorting	ascendingsort_remaining'tuple[MultiIndex, npt.NDArray[np.intp]]c           
        sV  t |ttfr
|g}fdd|D }d}t |tr4t|t|ks&tdtfdd|D |dnZtj tjt	 fdd|D }t	fd	d|D }t
|d
dD ]} | | qZ|rz||t	  7 }||t	 7 }n|d }t||dd|sddd tfddjD }t|jj|dd}	|	fS )a  
        Sort MultiIndex at the requested level.

        The result will respect the original ordering of the associated
        factor at that level.

        Parameters
        ----------
        level : list-like, int or str, default 0
            If a string is given, must be a name of the level.
            If list-like must be names or ints of levels.
        ascending : bool, default True
            False to sort in descending order.
            Can also be a list to specify a directed ordering.
        sort_remaining : sort by the remaining levels after level

        Returns
        -------
        sorted_index : pd.MultiIndex
            Resulting index.
        indexer : np.ndarray[np.intp]
            Indices of output values in original index.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([[0, 0], [2, 1]])
        >>> mi
        MultiIndex([(0, 2),
                    (0, 1)],
                   )

        >>> mi.sortlevel()
        (MultiIndex([(0, 1),
                    (0, 2)],
                   ), array([1, 0]))

        >>> mi.sortlevel(sort_remaining=False)
        (MultiIndex([(0, 2),
                    (0, 1)],
                   ), array([0, 1]))

        >>> mi.sortlevel(1)
        (MultiIndex([(0, 1),
                    (0, 2)],
                   ), array([1, 0]))

        >>> mi.sortlevel(1, ascending=False)
        (MultiIndex([(0, 2),
                    (0, 1)],
                   ), array([0, 1]))
        c                   r   rV   r   r   r   rV   rW   r   	  r   z(MultiIndex.sortlevel.<locals>.<listcomp>Nz(level must have same length as ascendingc                   r  rV   r  r   r   rV   rW   r   	  r   )ordersc                 3      | ]} | V  qd S r   rV   r   r  rV   rW   r   	  r  z'MultiIndex.sortlevel.<locals>.<genexpr>c                 3  r!  r   rV   r   )r  rV   rW   r   	  r  Treverser   F)compressr   c                   r  rV   r  r  r  rV   rW   r   	  r   )rU   r   rg   rs   rt   )r   rX  r   r   rx   ry   rA   rU   r  r   sortedri   r@   r'   rF   r   rg   )
rT   r   r  r  rs   primaryprimshpr   r   r*  rV   )rU   r  rT   r  rW   	sortlevel	  sD   6



zMultiIndex.sortlevelpreserve_namesc                 C  sf   t |ts+|d u r| }n|dk r| |}nzt|}W n ty*   | Y S w | ||}|S r   )r   rF   r   r[  r   rh   _maybe_preserve_names)rT   targetr  r)  rV   rV   rW   _wrap_reindex_result	  s   
zMultiIndex._wrap_reindex_resultr+  c                 C  s4   |r|j | j kr|j| jkr|jdd}| j|_|S )NFrB  )r   rg   rv   )rT   r+  r)  rV   rV   rW   r*  
  s   

z MultiIndex._maybe_preserve_namesc                 C  s   t |rt|rt|d S r   )r*   r,   r   r1  rV   rV   rW   _check_indexing_error
  s   z MultiIndex._check_indexing_errorc                 C  s   | j d jS )zA
        Should integer key(s) be treated as positional?
        r   )r   _should_fallback_to_positionalr   rV   rV   rW   r.  
  s   z)MultiIndex._should_fallback_to_positionalseriesc                 C  sb   |j | }t|r|S t|dkr| jdks|d S | | }t||}|j|||jd}||S )z
        Do a positional lookup on the given Series, returning either a scalar
        or a Series.

        Assumes that `series.index is self`
        rK   r   )r   rf   )r   r/   rx   r   maybe_droplevelsr"  rf   __finalize__)rT   r/  r  r-  
new_valuesr*  new_serrV   rV   rW   _get_values_for_loc 
  s   


zMultiIndex._get_values_for_loc	axis_name"tuple[Index, npt.NDArray[np.intp]]c                   s`   |}t |tst|}t|r)t |d ts)| |}| ||| | | |fS t 	||S r   )
r   r9   r   r   rx   r   _get_indexer_level_0_raise_if_missingr  _get_indexer_strict)rT   r-  r5  keyarrr  r  rV   rW   r9  4
  s   


zMultiIndex._get_indexer_strictc                   s   |}t |tst|}t|rAt |d tsA|dk}| r?| jd |}|dk}| r8t	||  dt	| dd S t
 |||S )Nr   r   z not in index)r   r9   r   r   rx   r   r   r   r  r  r  r8  )rT   r-  r  r5  r:  r]  checkcmaskr  rV   rW   r8  D
  s   

	zMultiIndex._raise_if_missingc                 C  s4   | j d }| jd }tj||d}t|}||S )z]
        Optimized equivalent to `self.get_level_values(0).get_indexer_for(target)`.
        r   )rU   
categories)r   r   r7   r  r9   get_indexer_for)rT   r+  r   rU   catcirV   rV   rW   r7  X
  s
   


zMultiIndex._get_indexer_level_0r  Hashable | Sequence[Hashable]sideLiteral['left', 'right']c                 C  s,   |  |dd t|ts|f}| j||dS )a  
        For an ordered MultiIndex, compute slice bound
        that corresponds to given label.

        Returns leftmost (one-past-the-rightmost if `side=='right') position
        of given label.

        Parameters
        ----------
        label : object or tuple of objects
        side : {'left', 'right'}
        kind : {'loc', 'getitem', None}

            .. deprecated:: 1.4.0

        Returns
        -------
        int
            Index of label.

        Notes
        -----
        This method only works if level 0 index of the MultiIndex is lexsorted.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([list('abbc'), list('gefd')])

        Get the locations from the leftmost 'b' in the first level
        until the end of the multiindex:

        >>> mi.get_slice_bound('b', side="left")
        1

        Like above, but if you get the locations from the rightmost
        'b' in the first level and 'f' in the second level:

        >>> mi.get_slice_bound(('b','f'), side="right")
        3

        See Also
        --------
        MultiIndex.get_loc : Get location for a label or a tuple of labels.
        MultiIndex.get_locs : Get location for a label/slice/list/mask or a
                              sequence of such.
        kindget_slice_boundrB  )_deprecated_argr   r   _partial_tup_index)rT   r  rB  rD  rV   rV   rW   rE  b
  s   4
zMultiIndex.get_slice_boundtuple[int, int]c                   s   |  |dd t |||S )a  
        For an ordered MultiIndex, compute the slice locations for input
        labels.

        The input labels can be tuples representing partial levels, e.g. for a
        MultiIndex with 3 levels, you can pass a single value (corresponding to
        the first level), or a 1-, 2-, or 3-tuple.

        Parameters
        ----------
        start : label or tuple, default None
            If None, defaults to the beginning
        end : label or tuple
            If None, defaults to the end
        step : int or None
            Slice step
        kind : string, optional, defaults None

            .. deprecated:: 1.4.0

        Returns
        -------
        (start, end) : (int, int)

        Notes
        -----
        This method only works if the MultiIndex is properly lexsorted. So,
        if only the first 2 levels of a 3-level MultiIndex are lexsorted,
        you can only pass two levels to ``.slice_locs``.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([list('abbd'), list('deff')],
        ...                                names=['A', 'B'])

        Get the slice locations from the beginning of 'b' in the first level
        until the end of the multiindex:

        >>> mi.slice_locs(start='b')
        (1, 4)

        Like above, but stop at the end of 'b' in the first level and 'f' in
        the second level:

        >>> mi.slice_locs(start='b', end=('b', 'f'))
        (1, 3)

        See Also
        --------
        MultiIndex.get_loc : Get location for a label or a tuple of labels.
        MultiIndex.get_locs : Get location for a label/slice/list/mask or a
                              sequence of such.
        rD  
slice_locs)rG  r  rJ  )rT   rp  endr  rD  r  rV   rW   rJ  
  s   8zMultiIndex.slice_locsleftrQ  r   c                 C  s  t || jkrtdt | d| j dt |}dt | }}t|| j| j}t|D ]\}\}}	}
|
|| }||	vrt|sz
tj	|	||d}W n t
y_ } zt
d| |d }~ww t|skt
d| |dkrw|dkrw|d8 }|tj	|||d   S | |	|}t|tr||d k r|j}|j}q,||d k r|tj	||dd }|tj	||d	d }q,t|tr|j}|tj	|||d   S |tj	|||d   S d S )
NKey length (z-) was greater than MultiIndex lexsort depth ()r   rF  zLevel type mismatch: rightrK   rL  )rx   r   r   r   r   rU   r   r6   r   searchsortedrh   r+   _get_loc_single_level_indexr   r  rp  r  )rT   rQ  rB  nrp  rK  zippedr  r  r   r   sectionr  r  r
  rV   rV   rW   rH  
  sN   

zMultiIndex._partial_tup_indexlevel_indexr
   c                 C  s   t |r
t|r
dS ||S )a  
        If key is NA value, location of index unify as -1.

        Parameters
        ----------
        level_index: Index
        key : label

        Returns
        -------
        loc : int
            If key is NA value, loc is -1
            Else, location of key in index.

        See Also
        --------
        Index.get_loc : The get_loc method for (single-level) index.
        r   )r/   r6   r/  )rT   rU  r-  rV   rV   rW   rQ    s   
z&MultiIndex._get_loc_single_level_indexc              
     s  |durt d |  fdd}t|ts# j|dd}||S t|} j|k r8td| d j d	| jkr` jr`z j	
|W S  ty_    |tt j\}}| Y S w  j}|d| ||d }}	|syd}
t }nz
 ||\}
}W n ty } zt||d}~ww |
|krt||	st|
|S tjd
tt d tj|
|tjd}t|	t|D ]$\}} j| |   j| |k}| s|| }t|st|qt|||
 kr||S t|
|S )a  
        Get location for a label or a tuple of labels.

        The location is returned as an integer/slice or boolean
        mask.

        Parameters
        ----------
        key : label or tuple of labels (one for each level)
        method : None

        Returns
        -------
        loc : int, slice object or boolean mask
            If the key is past the lexsort depth, the return may be a
            boolean mask array, otherwise it is always a slice or int.

        See Also
        --------
        Index.get_loc : The get_loc method for (single-level) index.
        MultiIndex.slice_locs : Get slice location given start label(s) and
                                end label(s).
        MultiIndex.get_locs : Get location for a label/slice/list/mask or a
                              sequence of such.

        Notes
        -----
        The key cannot be a slice, list of same-level labels, a boolean mask,
        or a sequence of such. If you want to use those, use
        :meth:`MultiIndex.get_locs` instead.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([list('abb'), list('def')])

        >>> mi.get_loc('b')
        slice(1, 3, None)

        >>> mi.get_loc(('b', 'e'))
        1
        NzEonly the default get_loc method is currently supported for MultiIndexc                   sb   t | tjr| jtjkr| S t| t } t | tr| S tj	t dd}|
d d|| < |S )z<convert integer indexer to boolean mask or slice if possibleru   r   FT)r   rP   r   r   r  r   maybe_indices_to_slicerx   r  emptyfill)r  r]  r   rV   rW   _maybe_to_sliceU  s   

z+MultiIndex.get_loc.<locals>._maybe_to_slicer   r8  rM  z) exceeds index depth (rN  z3indexing past lexsort depth may impact performance.r  r   )r  r-  r   r   _get_level_indexerrx   r   r  r   r  r/  rh   get_loc_levelr   r   r   rJ  r  r  r  r   r$   rP   r  r  r   rU   rQ  r   r   )rT   r-  methodrY  r  keylen_r   lead_key
follow_keyrp  r  r  r  r]  rV   r   rW   r/  #  sh   *


	



"zMultiIndex.get_loc
drop_levelc                   st   t |ttfs |}n	 fdd|D } j||d\}}|s6t|r2 ||d  }||fS  | }||fS )a  
        Get location and sliced index for requested label(s)/level(s).

        Parameters
        ----------
        key : label or sequence of labels
        level : int/level name or list thereof, optional
        drop_level : bool, default True
            If ``False``, the resulting index will not drop any level.

        Returns
        -------
        loc : A 2-tuple where the elements are:
              Element 0: int, slice object or boolean array
              Element 1: The resulting sliced multiindex/index. If the key
              contains all levels, this will be ``None``.

        See Also
        --------
        MultiIndex.get_loc  : Get location for a label or a tuple of labels.
        MultiIndex.get_locs : Get location for a label/slice/list/mask or a
                              sequence of such.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([list('abb'), list('def')],
        ...                                names=['A', 'B'])

        >>> mi.get_loc_level('b')
        (slice(1, 3, None), Index(['e', 'f'], dtype='object', name='B'))

        >>> mi.get_loc_level('e', level='B')
        (array([False,  True, False]), Index(['b'], dtype='object', name='A'))

        >>> mi.get_loc_level(['b', 'e'])
        (1, None)
        c                   r   rV   r   r   r   rV   rW   r     r   z,MultiIndex.get_loc_level.<locals>.<listcomp>r8  rK   )r   r   r   r   _get_loc_levelr   r+   )rT   r-  r   ra  r  r_  rV   r   rW   r[    s   &
zMultiIndex.get_loc_levelint | list[int]c              
     s  fdd}t |ttfrgt t|krtdd}t| D ]+\}}j||d\}}t |trAtj	tt
d}	d|	|< |	}|du rG|n||@ }q z
|||}
W ||
fS  tyf   | }
Y ||
fS w t  trpt  t  tr|dkrz jd v rj |d}||dg}||fW S W n ttfy   Y nw td	d
  D st jkrوjrz	j dfW S  ty } zt |d}~w ty   Y nw  } fddtt D }t|jkrt|r|dfS  fddtt D }t|jkrg }||||fS d}t D ]V\}}t |tsYj||d}t |trVt|sFt|trHq tj	tt
d}d||< n|}nt|raq td  |du rq|}q ||M }q |du rtdd} fddtt D }||||fS j |d}t  trj| jrj|  }t|s|| fS z|||g}W ||fS  ty   | }Y ||fS w )zX
        get_loc_level but with `level` known to be positional, not name-based.
        c                   s*    |  }t |ddD ]}||g}q
|S )z
            If level does not exist or all levels were dropped, the exception
            has to be handled outside.
            Tr"  )r%  _drop_level_numbers)r  r   r*  r   r   rV   rW   maybe_mi_droplevels  s   z6MultiIndex._get_loc_level.<locals>.maybe_mi_droplevelsz:Key for location must have same length as number of levelsNr8  r   Tr   c                 s  s    | ]}t |tV  qd S r   )r   r  r  rV   rV   rW   r     rH  z,MultiIndex._get_loc_level.<locals>.<genexpr>c                   "   g | ]} | t d d kr|qS r   r  rC  r  rV   rW   r        " z-MultiIndex._get_loc_level.<locals>.<listcomp>c                   s<   g | ]}t  | trj| js | td d kr|qS r   )r   rX  r   !_supports_partial_string_indexingr  rC  r-  rT   rV   rW   r   %  s    
z'Expected label or tuple of labels, got c                   rf  r   rg  rC  r  rV   rW   r   U  rh  )r   r   r   rx   r  r   rb  r  rP   r   ru   ry   r   rZ  rh   r   r   r   r   r  r/  r  r   r+   r   r   is_null_sliceis_full_slicerX  ri  )rT   r-  r   re  r   r   r  r  r*  r]  r_  r  r  ilevelsr   	loc_levelk_indexr;  result_indexrV   rj  rW   rb    s   






	






zMultiIndex._get_loc_levelr  npt.NDArray[np.bool_] | Nonec                 C  s\  | j | }| j| }||fdd}t|tr|j}|d uo |dk }z:|jd ur.||j}	n|r7t|d }	nd}	|jd urE||j}
n|rJd}
nt|	trTt|}
nt|d }
W n t	ys   |
|j|j|j }	}
|	j}Y nw t|	ts~t|
trt|	d|	}	t|
d|
}
||	|
|S |dks| jdks|d ur|r|
d n|
d }
||	|
|S tj||	dd}tj||
d	d}t|||S | ||}|dks| jdkrt|tr||jk||jk @ }|S tj||ktd
d}| st	||S t|trtj||jdd}	tj||jdd}ntj||dd}	tj||d	d}|	|kr)t	|t|	|S )Nc                 S  sr   |d ur|| }|d u s|dkr|| k||k @ }nt j| |||jd}t||}|d u r/|S | }|||< |S )NrK   r   )rP   r  r   r   r  rv   )rp  r  r  r  rU   new_indexerrrV   rV   rW   convert_indexeru  s   z6MultiIndex._get_level_indexer.<locals>.convert_indexerr   rK   rp  r  rL  rF  rO  F)r   rv   )r   rU   r   r  r  rp  r/  rx   r  r  slice_indexerr   r   r   rP  rQ  rP   r   ru   r   )rT   r-  r   r  rU  r   rt  r  is_negative_steprp  r  r   r  r
  locsrK  rV   rV   rW   rZ  j  sf   










zMultiIndex._get_level_indexerc                   sP  dd t t|D }|r |d | jkr td| d| j tdd |D r-tdt|  d fdd}d}t |D ]\}}d}t|rYt| krSt	dt
|}nt|rz
| j|||d}W nT tttfy } zE|D ]<}	t|	s||z
| j|	||d}
W n ty   tjdtt d Y qtw |du r||
}qtt|
trd||
< qt||
O }qtW Y d}~nd}~ww |du rt
jg t
jd  S n$t|r|du r|t|d krt
j t
jd  S q>| j|||d}||}|du r|}q>||M }t
|st
|rt|q>|du rt
jg t
jdS | d }| ||S )a  
        Get location for a sequence of labels.

        Parameters
        ----------
        seq : label, slice, list, mask or a sequence of such
           You should use one of the above for each level.
           If a level should not be used, set it to ``slice(None)``.

        Returns
        -------
        numpy.ndarray
            NumPy array of integers suitable for passing to iloc.

        See Also
        --------
        MultiIndex.get_loc : Get location for a label or a tuple of labels.
        MultiIndex.slice_locs : Get slice location given start label(s) and
                                end label(s).

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([list('abb'), list('def')])

        >>> mi.get_locs('b')  # doctest: +SKIP
        array([1, 2], dtype=int64)

        >>> mi.get_locs([slice(None), ['e', 'f']])  # doctest: +SKIP
        array([1, 2], dtype=int64)

        >>> mi.get_locs([[True, False, True], slice('e', 'f')])  # doctest: +SKIP
        array([2], dtype=int64)
        c                 S  s   g | ]\}}|r|qS rV   rV   )r   r   srV   rV   rW   r     r   z'MultiIndex.get_locs.<locals>.<listcomp>r   zIMultiIndex slicing requires the index to be lexsorted: slicing on levels z, lexsort depth c                 s  s    | ]}|t u V  qd S r   )Ellipsisr  rV   rV   rW   r     r  z&MultiIndex.get_locs.<locals>.<genexpr>z2MultiIndex does not support indexing with Ellipsisre   r  c                   s*   t | trtj tjd}d|| < |S | S )Nr   T)r   r  rP   r   bool_)r  rr  rR  rV   rW   _to_bool_indexer  s
   
z-MultiIndex.get_locs.<locals>._to_bool_indexerNzLcannot index with a boolean indexer that is not the same length as the index)r   r  a5  The behavior of indexing on a MultiIndex with a nested sequence of labels is deprecated and will change in a future version. `series.loc[label, sequence]` will raise if any members of 'sequence' or not present in the index's second level. To retain the old behavior, use `series.index.isin(sequence, level=1)`r  Tr   rK   r   re   r  )r   r   is_true_slicesr   r   r   r  rx   r  ry   rP   r   r-   rZ  r   rh   r  r*   r  r  r  r$   r   r  r   r  rk  r  r  _reorder_indexer)rT   seqtrue_slicesr|  r  r   r  lvl_indexerr  r   item_indexerpos_indexerrV   r{  rW   get_locs  s   $






'

zMultiIndex.get_locsr  ,tuple[Scalar | Iterable | AnyArrayLike, ...]c                 C  s  |   rGd}t|D ]8\}}t|r1|s0| j| |}||dk }|dd |dd k }q
t|trB|jdurB|jdk rBd}q
|sG|S t	| }d}t|D ]\}}t
|r\|g}t|rit|| }	nyt|rt|}tjt	| j| tjdt	| j|  }
| j| |}||dk }tt	||
|< |
| j| |  }	n;t|tr|jdur|jdk rt|ddd | }	nt|tr|jdu r|jdu rt|f| }	nt|| }	|	f| }qQt|}|| S )	am  
        Reorder an indexer of a MultiIndex (self) so that the labels are in the
        same order as given in seq

        Parameters
        ----------
        seq : label/slice/list/mask or a sequence of such
        indexer: a position indexer of self

        Returns
        -------
        indexer : a sorted position indexer of self ordered as seq
        Fr   Nr   rK   TrV   r   )r  r   r-   r   r  r   r   r  r  rx   r/   r   r  rP   r  r   r  onesr  rU   rp  r  r  )rT   r  r  	need_sortr   r  k_codesrR  keys	new_orderkey_order_maplevel_indexerindrV   rV   rW   r  s  sL   


zMultiIndex._reorder_indexerc                   s   |r|r||k rt d| jd ||\}}| ||\ t| j}|d || |d<  fdd| jD }|d | |d< t||| jddS )av  
        Slice index between two labels / tuples, return new MultiIndex

        Parameters
        ----------
        before : label or tuple, can be partial. Default None
            None defaults to start
        after : label or tuple, can be partial. Default None
            None defaults to end

        Returns
        -------
        truncated : MultiIndex
        zafter < beforer   c                   s   g | ]}|  qS rV   rV   r  rL  rO  rV   rW   r     r   z'MultiIndex.truncate.<locals>.<listcomp>Fr  )ry   r   rJ  r   rU   rF   rq   )rT   beforeafterr   r  r   r   rV   r  rW   truncate  s   
zMultiIndex.truncater  ra   c           	      C  sN  |  |rdS t|tsdS t| t|krdS t|ts+| |s$dS t| j|jS | j|jkr3dS t	| jD ]l}| j
| }|j
| }|dk}|dk}t||sU dS ||  }| j| j|}||  }|j| j|}t|dkr~t|dkr~q8t|tjs||s dS q8t|tjs||s dS q8t||s dS q8dS )z
        Determines if two MultiIndex objects have the same labeling information
        (the levels themselves do not necessarily have to be the same)

        See Also
        --------
        equal_levels
        TFr   r   )is_r   r9   rx   rF   _should_comparer5   r   r   r   rU   rP   array_equalr   r[  r   equals)	rT   r  r   
self_codesother_codes	self_mask
other_maskself_valuesother_valuesrV   rV   rW   r    sJ   
	









zMultiIndex.equalsc                 C  s@   | j |j krdS t| j D ]}| j| |j| s dS qdS )zT
        Return True if the levels of both MultiIndex objects are the same

        FT)r   r   r   r  )rT   r  r   rV   rV   rW   equal_levels  s   zMultiIndex.equal_levelsc                   s   |  |\}}tdd | jD rtdd |jD s!| js!|jr)t ||}n|jjtdd}t	j
| j|g|d}tjt| d |dS )Nc                 s  r  r  rV   r  rV   rV   rW   r   /  r  z$MultiIndex._union.<locals>.<genexpr>c                 s  r  r  rV   r  rV   rV   rW   r   0  r  Fr   )r  r   )_convert_can_do_setopr   rU   has_duplicatesr  _unionr   rb   ra   r   fast_unique_multiplerF   r   r   )rT   r  r  result_namesr   rvalsr  rV   rW   r  ,  s   zMultiIndex._unionr   r   c                 C  s   t |S r   )r.   r+  rV   rV   rW   _is_comparable_dtype=  s   zMultiIndex._is_comparable_dtypec                 C  s"   |  |}| j|kr| |S | S )z
        If the result of a set operation will be self,
        return self, unless the names change, in which
        case make a shallow copy of self.
        )_maybe_match_namesrg   rename)rT   r  rg   rV   rV   rW   _get_reconciled_name_object@  s   


z&MultiIndex._get_reconciled_name_objectc                 C  sb   t | jt |jkrdgt | j S g }t| j|jD ]\}}||kr)|| q|d q|S )z
        Try to find common names to attach to the result of an operation between
        a and b. Return a consensus list of names if they match at least partly
        or list of None if they have completely different names.
        N)rx   rg   r   r   )rT   r  rg   a_nameb_namerV   rV   rW   r  M  s   zMultiIndex._maybe_match_namesc                 C  sH   |  |\}}t|dkrt| jg g| j |ddS tjt| d|dS Nr   Fr  r   )r  rx   rF   r   r   r   r   rT   r  r   r^  r  rV   rV   rW   _wrap_intersection_result^  s   
z$MultiIndex._wrap_intersection_resultc                 C  sJ   |  |\}}t|dkrtg g| j g g| j |ddS tj|d|dS r  )r  rx   rF   r   r   r  rV   rV   rW   _wrap_difference_resultk  s   

z"MultiIndex._wrap_difference_resultc              
   C  s   | j }t|ts:t|dkr| d d | j fS d}ztj|| j d}W ||fS  ttfy9 } zt||d }~ww t| |}||fS )Nr   z.other must be a MultiIndex or a list of tuplesr  )	rg   r   r9   rx   rF   r   ry   rh   r<   )rT   r  r  r	  r  rV   rV   rW   r  x  s   


z MultiIndex._convert_can_do_setopc                 C  s@   t |}t|rd}t|t|std|du r|  S | S )Nz3> 1 ndim Categorical are not supported at this timezISetting a MultiIndex dtype to anything other than object is not supportedT)r0   r(   r  r.   rh   r   )rT   r   rv   r	  rV   rV   rW   rb     s   zMultiIndex.astypec                 C  s`   t |tr|j| jkrtd|jS t |ts#|fd| jd   }|S t|| jkr.td|S )Nz0Item must have length equal to number of levels.)ro  rK   )r   rF   r   ry   r   r   rx   )rT   itemrV   rV   rW   _validate_fill_value  s   

zMultiIndex._validate_fill_valuer  c           	      C  s   |  |}g }g }t|| j| jD ]*\}}}||vr%t|}|||}n||}|| |tt	||| qt
||| jddS )a  
        Make new MultiIndex inserting new item at location

        Parameters
        ----------
        loc : int
        item : tuple
            Must be same length as number of levels in the MultiIndex

        Returns
        -------
        new_index : Index
        Fr  )r  r   r   rU   rx   insertr/  r   rP   r&   rF   rg   )	rT   r  r  r   r   r  r   r   lev_locrV   rV   rW   r    s   



zMultiIndex.insertc                   s(    fdd| j D }t| j|| jddS )z}
        Make new index with passed location deleted

        Returns
        -------
        new_index : MultiIndex
        c                   s   g | ]}t | qS rV   )rP   r  r  r  rV   rW   r     r   z%MultiIndex.delete.<locals>.<listcomp>Fr  )rU   rF   r   rg   )rT   r  r   rV   r  rW   r    s   zMultiIndex.deletec                 C  sd   |d u rt j|| jdj}t| j|S | |}| |}|jdkr-t	j
t|t	jdS ||S )Nr  r   r   )rF   r   rg   r   r   r  r   r  sizerP   r   rx   rz  )rT   r   r   numlevsrV   rV   rW   r    s   



zMultiIndex.isinr	  MultiIndex | Nonec                   s   t  j|||dS )N)rg   r   r	  )r  	set_names)rT   rg   r   r	  r  rV   rW   r    s   zMultiIndex.set_namesr  
str | boolc                   s   t  j|dS )N)r  )r  drop_duplicates)rT   r  r  rV   rW   r    s   zMultiIndex.drop_duplicates__add____radd____iadd____sub____rsub____isub____pow____rpow____mul____rmul____floordiv____rfloordiv____truediv____rtruediv____mod____rmod__
__divmod____rdivmod____neg____pos____abs__
__invert__)NNNNNFNT)rt   ru   re   rF   )r   r   r   r   )NN)rU   r   r   r   )re   rF   )r   r   rs   rr   rg   r   re   rF   )r   r   rs   rr   rg   r   re   rF   )r   rD   re   rF   )re   r   )re   rE   )re   r   )re   r=   )rv   ru   rw   ru   rt   ru   re   r   )NNT)rt   ru   )re   r   )re   r   )r   r   re   rF   )NNNNFNr   )r-  r   re   ru   )re   r3  )re   ru   F)r%  ru   re   r   )re   rU  )NNNFr`  NT)rf   ra  rb  rc  rT  rd  rg   ru   re  r   rf  ru   re   r   )rw   ru   )r  ru   re   r  re   rX  )re   r  )r  r}  )r   )r  rX  re   rF   )r   r   r  ru   re   r9   )r   ru   r  ru   re   rD   )re   r9   )rT   rF   r  r  re   rF   )r   TN)rT   rF   rM   r   r  ru   re   rF   )re   r  )r  r   re   rF   )Nr  )r  )r  r   )re   r  )r   TT)r  ru   r  ru   re   r  )r)  ru   )r+  r9   r)  ru   re   r9   )re   r   )r/  rE   )r5  rX  re   r6  )r5  rX  re   r   )r  rA  rB  rC  re   r   )re   rI  )rL  )rQ  r   rB  rC  )rU  r9   r-  r
   re   r   )r   T)ra  ru   )r   )r   rc  )r   N)r   r   r  rq  )r  r  r  r  re   r  )r  ra   re   ru   )r  rF   re   ru   )r   r   re   ru   )T)rv   ru   )r  r   re   rF   )NF)r	  ru   re   r  )r  r  re   rF   )rY   rZ   r[   r\   r9   _hidden_attrs	frozenset_typrq   __annotations__r=   r   r   _comparablesrz   r   r   classmethodr   r   r   ro   r   r   r   r!   r   propertyr   r   r   r   r   r|   r"   r  r   r  rU   r}   r  r  r"  r#   r$  r   rv   r,  r  r2  r   r<  r?  r@  r>  rN  rW  rt  r  r~   rg   r  r  r   r  r  r;  r   _duplicatedr  r  r  r  r  r  r  r  r  r  r   r  r  r  r  r  r    r:   _index_doc_kwargsr[  r   r  r  r
  r   r  r  r  r(  r,  r*  r-  r.  r4  r9  r8  r7  rE  rJ  rH  rQ  r/  r[  rb  rZ  r  r  r  r  r  r  r  r  r  r  r  r  rb   r  r  r  r  r  r  r  r>   r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  __classcell__rV   rV   r  rW   rF      s  
 M/>AO?A#
	*p
%R
[&N:4
g	"	CZ""6:.l
;=2}3 s I">#




















rU   list[np.ndarray]r   r   c                 C  s>   dd | D }t |ddD ]}t|d| r|  S qdS )zJCount depth (up to a maximum of `nlevels`) with which codes are lexsorted.c                 S  r   rV   )r&   r  rV   rV   rW   r     r   z"_lexsort_depth.<locals>.<listcomp>r   r   N)r   r  r  )rU   r   int64_codesr  rV   rV   rW   r     s   r   ro  rp  c                 C  s   t t|  }t| }|d |d  }|| }||d d  D ]>}g }tt||D ]0\}	\}
}|	|d krA|| ||  n|
|krK|| q)|||	d   ||  |}qt t| S )NrK   )r   r   rx   r   r   rv  )
label_listrp  rq  pivotedr  r   prevcur
sparse_curr   ptrV   rV   rW   rw    s$   


rw  rX  c                 C  s.   t | r| j S | j} tjdtjdi| dS )NNaTNaN)r)   r  r!  rP   
datetime64timedelta64getr   rV   rV   rW   rs  6  s   rs  r   r9   c              	   C  sn   | }t |tr#|D ]}z| dg} W q	 ty    | Y   S w | S z	| dg} W | S  ty6   Y | S w )z
    Attempt to drop level or levels from the given index.

    Parameters
    ----------
    index: Index
    key : scalar or tuple

    Returns
    -------
    Index
    r   )r   r   rd  ry   )r   r-  original_indexr^  rV   rV   rW   r0  ?  s    
	r0  Frv   ru   r   c                 C  s"   t | |} |r|  } d| j_| S )a  
    Coerce the array-like indexer to the smallest integer dtype that can encode all
    of the given categories.

    Parameters
    ----------
    array_like : array-like
    categories : array-like
    copy : bool

    Returns
    -------
    np.ndarray
        Non-writeable.
    F)r%   rv   rY  rZ  )
array_liker=  rv   rV   rV   rW   r  ^  s
   
r  arrnamec                 C  s   | dur*t | s*t |st| dt |d r t| d| g} |g}| |fS | du s2t | rCt |r<t |d sCt| d| |fS )zT
    Ensure that level is either None or listlike, and arr is list-of-listlike.
    Nz must be list-liker   z must be list of lists-like)r-   rh   )r   r   r  rV   rV   rW   r  u  s   r  )rd   r   re   r   )rU   r  r   r   re   r   )r   ro  )rp  r   r  )r   r9   re   r9   r  )rv   ru   re   r   )r  rX  ){
__future__r   	functoolsr   sysr   typingr   r   r   r	   r
   r   r   r   r   r   r   r  numpyrP   pandas._configr   pandas._libsr   r  r   r]   r   pandas._libs.hashtabler   pandas._typingr   r   r   r   r   r   pandas.compat.numpyr   r  pandas.errorsr   r   r   pandas.util._decoratorsr    r!   r"   r#   pandas.util._exceptionsr$   pandas.core.dtypes.castr%   pandas.core.dtypes.commonr&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   pandas.core.dtypes.dtypesr1   pandas.core.dtypes.genericr2   r3   r4   pandas.core.dtypes.missingr5   r6   pandas.core.algorithmscore
algorithmspandas.core.arraysr7   pandas.core.arrays.categoricalr8   pandas.core.commoncommonr   pandas.core.indexes.baseindexesbaser  r9   r:   r;   r<   pandas.core.indexes.frozenr=   pandas.core.ops.invalidr>   pandas.core.sortingr?   r@   rA   pandas.io.formats.printingrB   r   rC   rD   rE   dictr  updateBaseMultiIndexCodesEnginer^   rJ   rc   r`   ro   rF   r   rw  rs  r0  r  r  rV   rV   rV   rW   <module>   s    4 4
'
)                            
[	

	