B
    W0d                @  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 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" d d
l#m$Z% d dl&m'Z'm(Z(m)Z) d dl*m+Z+m,Z,m-Z-m.Z. d dl/m0Z0 d dl1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z; d dl<m=Z= d dl>m?Z?m@Z@mAZA d dlBmCZCmDZD d dlEmF  mGZ d dlHmIZI d dlJmKZK d dlLmF  mMZN d dlOmPZP d dlQmF  mR  mSZT d dlQmUZUmVZVmWZWmXZX d dlYmZZZ d dl[m\Z\ d dl]m^Z^ d dl_m`Z`maZambZb d dlcmdZd er"d dlemfZfmgZgmhZh eieTjjZjejkddd G dd  d ejlejmZnG d!d" d"ejlejoZpd#d$ ZqG d%d deUZrd&d'd'd(d)d*Zsd@d'd,d-d.Ztd/d0d1d2Zud3d3d4d5d6ZvdAd8d9d:d;d<Zwd/d=d>d?ZxdS )B    )annotations)wraps)	getsizeof)
TYPE_CHECKINGAnyCallable
CollectionHashableIterableListSequenceTuplecastN)
get_option)algosindexlib)
duplicated)AnyArrayLikeDtypeObjScalarShape)function)InvalidIndexErrorPerformanceWarningUnsortedIndexError)Appendercache_readonlydeprecate_nonkeyword_argumentsdoc)coerce_indexer_dtype)
ensure_int64ensure_platform_intis_categorical_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)is_empty_indexer)Index_index_shared_docsensure_indexget_unanimous_names)
FrozenList)
Int64Index)make_invalid_op)get_group_indexindexer_from_factorizedlexsort_indexer)pprint_thing)CategoricalIndex	DataFrameSeries
MultiIndexzMultiIndex or list of tuples)klassZtarget_klassc               @  s   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 rN   K/var/www/html/venv/lib/python3.7/site-packages/pandas/core/indexes/multi.py_codes_to_intst   s    

z#MultiIndexUIntEngine._codes_to_intsN)__name__
__module____qualname____doc__libindexUInt64Engine_baserP   rN   rN   rN   rO   rD   l   s   rD   c               @  s   e Zd ZdZejZdd ZdS )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).
        objectrE   )rF   )astyperG   rH   rI   rJ   rK   )rL   rM   rN   rN   rO   rP      s    
z$MultiIndexPyIntEngine._codes_to_intsN)rQ   rR   rS   rT   rU   ObjectEnginerW   rP   rN   rN   rN   rO   rX      s   rX   c               s   t   fdd}|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               s@   d|krd|krt dnd|kr0|d|d<  | f||S )Nnamenamesz*Can only provide one of `names` and `name`)	TypeErrorpop)Zself_or_clsargskwargs)methrN   rO   new_meth   s
    
znames_compat.<locals>.new_meth)r   )rb   rc   rN   )rb   rO   names_compat   s    	rd   c            	      sD	  e Zd ZU dZeje B ZdZe Z	e Z
e ZdgZded< dLd	d
ddZdddddZdMdddddZedejfd dddZeedNdddd dddZedejfd dddZedOdd d d!d"Zed#dd$d%Zed#dd&d'Zed(d) Zed*dd+d,Zd-dd.d/Zed0dd1d2Z dPd	d	d	d3d4d5d6Z!e"dd7d8gd9dQd	d
d:d;Z#ed-dd<d=Z$ed>dd?d@Z%edAdB Z&dRd	d	d	d3d4dCdDZ'e"dd7dEgd9dSd	d
dFdGZ(edHdI Z)edJddKdLZ*e+ej,ejfd#d dMdNdOZ,d ddPdQZ-dTdRdSZ.dUd#ddTdUZ/dVdVdWZ0e+ej1dXd	dYdZd[Z1ed\dd]d^Z2d	dd_d`Z3e+ej4dWd	d-dadbdcZ4ed-ddddeZ5dXd	d-dadfdgZ6dhdi Z7dYdkdlZ8dZdndodpd	d-d	ddqdrdsZ9d0ddtduZ:d[d	dvdwdxZ;ee;e:dydzZ<e+ej=d{d| Z=ed}dd~dZ>d-dddZ?ed	dddZ@ed	dddZAed	dddZBeddddZCe+ejDd\d#dddZDeDZEd]ddZFe+ejGd^d}d dddZGd_d-d	ddddZHdd ZIe+ejJd` fdd	ZJdad	ddddZKddddZLed	dddZMd	dddZNd	dddZOedd ZPed-dddZQd dddZRd dddZSdd ZTdd ZUd dd dddZVeWeXd eY dbd d-d	d dddZZdd Z[d#dddZ\eWeXd eY dcd-d dddÄZ]ddddƄZ^ded dddȄZ_dfd ddd̄Z`d ddd΄ZaddddфZbdgd	d	ddӜddՄZcdhdddd؄Zdddڄ Zed	ddd܄Zfd*dݜdd߄ZgddddZhdd Zididdpdd#dddZjdjdd}dpd-dddZkdk fdd	ZldlddddZmddd-dddZndmddZodnd	dddZpdodd	dddZqdpd-d ddZrdd Zsdddddd	Ztdqd dd
dZudd	dddZvd d	dddZwd d fddZxdd	dddZyd dddZzdd Z{dd Z|d d fddZ}d d! Z~e+ejdrd	d"d#d$Zd%d& Zd-d d'd(d)Zd dd*d+Ze+ejdsd#dd,d-Ze"dd7dgd9dtd	d.d/ fd0d1ZeZe"dd7gd9dud2d d3 fd4d5Zed6Zed7Zed8Zed9Zed:Zed;Zed<Zed=Zed>Zed?Zed@ZedAZedBZedCZedDZedEZedFZedGZedHZedIZedJZedKZ  ZS (v  rB   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.
    Z
multiindexr]   z
int | None	sortorderNFTbool)verify_integrityc	             C  s   |d k	r|}|d ks|d kr$t dt|t|kr<tdt|dkrPtdt| }	i |	_|	j||dd |	j||dd d gt| |	_|d k	r|		| |d k	rt
||	_n||	_|r|	 }
|
|	_|	  |	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)r^   len
ValueErrorrY   __new___cache_set_levels
_set_codes_names
_set_namesintre   _verify_integrity_codes_reset_identity)clslevelsrM   re   r]   dtyperh   r\   rg   result	new_codesrN   rN   rO   rl   +  s.    

zMultiIndex.__new__list)level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).
        )r0   rI   anywhere)rL   r|   r}   Z	null_maskrN   rN   rO   _validate_codesZ  s    
zMultiIndex._validate_codeszlist | None)rM   rw   c          	     sj  |p j }|p j}t|t|kr,tdt|d }xtt||D ]\}\}}t||krxtddd |D  t|r| t|krtd| d|  dt| d	t|r| d
k rtd| d|  d|jsHtdt	| d| qHW  j
dk	rF j
t j  jkrFt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  s   g | ]}t |qS rN   )rj   ).0Zcode_rN   rN   rO   
<listcomp>  s    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 rN   )r   )r   r|   r}   )rL   rN   rO   r     s    )rM   rw   rj   rk   	enumeratezipmaxmin	is_uniquer{   re   _lexsort_depthnlevelsr8   )rL   rM   rw   Zcodes_lengthir|   level_codesrz   rN   )rL   rO   rs   o  s2    

"zMultiIndex._verify_integrity)returnc       	      C  s   d}t |st|nt|r&t|}x|D ]}t |s,t|q,W x:tdt|D ](}t|| t||d  krTtdqTW t|\}}|tj	krd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.rE   zall arrays must be same lengthc             S  s   g | ]}t |d dqS )r\   N)getattr)r   arrrN   rN   rO   r     s    z*MultiIndex.from_arrays.<locals>.<listcomp>F)rw   rM   re   r]   rg   )
r'   r^   r&   r{   rangerj   rk   r2   r   
no_default)	rv   arraysre   r]   	error_msgarrayr   rM   rw   rN   rN   rO   from_arrays  s(    %


zMultiIndex.from_arrayszIterable[tuple[Hashable, ...]]zSequence[Hashable] | None)tuplesre   r]   r   c             C  s   t |stdnt|r"t|}ttttdf  |}t|dkrd|dkrTtdg gt| }nnt	|t
jtfrt	|trt
|j}tt|j}n6t	|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..r   Nz-Cannot infer number of levels from empty list)re   r]   )r'   r^   r&   r{   r   r   r   r	   rj   
isinstancerI   ndarrayr4   asarray_valuesr   Ztuples_to_object_arrayTZto_object_array_tuplesr   r   r   r   )rv   r   re   r]   r   ZarrsrN   rN   rO   from_tuples  s$    +


zMultiIndex.from_tuplesc             C  sj   ddl m} t|stdnt|r.t|}t|\}}|tjkrRd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  s   g | ]}t |d dqS )r\   N)r   )r   itrN   rN   rO   r   i  s    z+MultiIndex.from_product.<locals>.<listcomp>)re   r]   )	Zpandas.core.reshape.utilr   r'   r^   r&   r{   r2   r   r   )rv   	iterablesre   r]   r   rM   rw   rN   rN   rO   from_product2  s    .

zMultiIndex.from_productr@   )dfr   c             C  sB   t |tstdt|  \}}|dk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 DataFrameN)re   r]   )r   r,   r^   r   itemsr   )rv   r   re   r]   Zcolumn_namescolumnsrN   rN   rO   
from_frameo  s
    9
zMultiIndex.from_framez
np.ndarrayc             C  s   g }xvt | jD ]h}| |}t|jr<td|}|j }t|jt	sVt|t
tfr`|t}tj|dd}|| qW t|}|S )Nr?   F)rh   )r   r   _get_level_valuesr#   rx   r   _dataZ_internal_get_valuesr   r+   r-   r.   rZ   rY   rI   r   appendr   Zfast_zip)rL   valuesr   valsr   rN   rN   rO   r     s    





zMultiIndex._valuesc             C  s   | j S )N)r   )rL   rN   rN   rO   r     s    zMultiIndex.valuesc             C  s   t ddS )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.N)rk   )rL   rN   rN   rO   r     s    
zMultiIndex.arrayrA   c             C  s$   ddl m} |dd t| jD S )zM
        Return the dtypes as a Series for the underlying MultiIndex
        r   )rA   c             S  s.   i | ]&\}}|j |jd kr$d| n|jqS )NZlevel_)rx   r\   )r   idxr|   rN   rN   rO   
<dictcomp>  s   z%MultiIndex.dtypes.<locals>.<dictcomp>)pandasrA   r   rw   )rL   rA   rN   rN   rO   dtypes  s    zMultiIndex.dtypesrr   c             C  s   t | jd S )Nr   )rj   rM   )rL   rN   rN   rO   __len__  s    zMultiIndex.__len__r8   c             C  s4   dd t | j| jD }x|D ]
}d|_qW t|S )Nc             S  s   g | ]\}}|j |d qS ))r\   )Z_rename)r   xr\   rN   rN   rO   r     s    z%MultiIndex.levels.<locals>.<listcomp>T)r   _levelsrp   Z_no_setting_namer8   )rL   ry   r|   rN   rN   rO   rw     s    

zMultiIndex.levelsNone)rh   ri   rg   r   c               s  |rVt |dkrtd|d kr6t |jkr6td|d k	rVt |t |krVtd|d krvt fdd|D }nPfdd|D }tj}x*t||D ]\}	}
t|
 d	 ||	< qW t|}|r܈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 ))rh   N)r6   _view)r   lev)rh   rN   rO   	<genexpr>  s    z)MultiIndex._set_levels.<locals>.<genexpr>c               s   g | ]}  |qS rN   )_get_level_number)r   r   )rL   rN   rO   r     s    z*MultiIndex._set_levels.<locals>.<listcomp>)rh   )rw   )rj   rk   r   r8   r{   r   r   r6   r   rs   rt   r]   r   rq   _reset_cache)rL   rw   r|   rh   ri   rg   
new_levelslevel_numbersZnew_levels_listlev_numr   rz   r]   rN   )rh   rL   rO   rn     s.    

zMultiIndex._set_levelsrL   rw   )versionZallowed_argsc             C  s   |dk	rt jdtdd nd}t|r8t|ts8t|}t||d\}}|rR| }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]])
        Nz>inplace is deprecated and will be removed in a future version.   )
stacklevelFZLevelsT)r|   ri   rg   )warningswarnFutureWarningr'   r   r4   r{   _require_listliker   ru   rn   )rL   rw   r|   inplacerg   r   rN   rN   rO   
set_levels"  s"    X
zMultiIndex.set_levelsc             C  s
   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
        )rj   r   )rL   rN   rN   rO   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  s   | ]}t |V  qd S )N)rj   )r   r   rN   rN   rO   r     s    z&MultiIndex.levshape.<locals>.<genexpr>)tuplerw   )rL   rN   rN   rO   levshape  s    zMultiIndex.levshapec             C  s   | j S )N)rt   )rL   rN   rN   rO   rM     s    zMultiIndex.codesc               s   |rB|d kr"t |jkr"td|d k	rBt |t |krBtd|d krjt fddtj|D }nXfdd|D }tj}x2t||D ]$\}	}
j|	 }t	|
| d||	< qW t|}|r҈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 ))rh   N)_coerce_indexer_frozenview)r   r   r   )rh   rN   rO   r     s   z(MultiIndex._set_codes.<locals>.<genexpr>c               s   g | ]}  |qS rN   )r   )r   r   )rL   rN   rO   r     s    z)MultiIndex._set_codes.<locals>.<listcomp>)rh   )rM   )rj   r   rk   r8   r   r   r{   rt   rw   r   rs   r   )rL   rM   r|   rh   ri   rg   rz   r   Znew_codes_listr   r   r   rN   )rh   rL   rO   ro     s(    


zMultiIndex._set_codesrM   c             C  sd   |dk	rt jdtdd nd}t||d\}}|r8| }n|  }|  |j|||d |s`|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'])
        Nz>inplace is deprecated and will be removed in a future version.r   )r   FZCodes)r|   rg   )r   r   r   r   r   ru   ro   )rL   rM   r|   r   rg   r   rN   rN   rO   	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rtt| j| j|S t	| j| j|S )Nc             S  s   g | ]}t |d  qS )rE   )rj   )r   r|   rN   rN   rO   r   5  s    z&MultiIndex._engine.<locals>.<listcomp>r~   rE   r   uint64@   )
rI   ceillog2rw   ZcumsumconcatenaterZ   rX   rM   rD   )rL   sizesZlev_bitsrG   rN   rN   rO   _engine1  s    zMultiIndex._enginezCallable[..., MultiIndex]c             C  s
   t | jS )N)typer   )rL   rN   rN   rO   _constructorG  s    zMultiIndex._constructor)r   r   c             C  s(   |t jk	r|n| j}t| j|d |dS )N)re   r]   )r   r   r]   r   r   )rL   r   r\   r]   rN   rN   rO   _shallow_copyK  s    zMultiIndex._shallow_copyc             C  s<   t | | j| j| j| jdd}| j |_|jdd  |S )NF)rw   rM   re   r]   rg   rw   )r   rw   rM   re   r]   rm   rh   r_   )rL   ry   rN   rN   rO   r   Q  s    zMultiIndex._viewc       	      C  s   | j |||d}|dk	r(tjdtdd |dk	r@tjdtdd |rtddlm} |dkrb|| j}|dkrt|| j}|dk	r|n| j}|dk	r|n| j}t| ||| j	|d	d
}| j
 |_
|j
dd |rtjdtd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.
        )r\   r]   deepNzjparameter levels is deprecated and will be removed in a future version. Use the set_levels method instead.   )r   zhparameter codes is deprecated and will be removed in a future version. Use the set_codes method instead.r   )deepcopyF)rw   rM   re   r]   rg   rw   zeparameter dtype is deprecated and will be removed in a future version. Use the astype method instead.)Z_validate_namesr   r   r   rh   r   rw   rM   r   re   rm   r_   rZ   )	rL   r]   rx   rw   rM   r   r\   r   	new_indexrN   rN   rO   rh   _  sD    '


zMultiIndex.copyc             C  s   | j S )z%the array interface, return my values)r   )rL   rx   rN   rN   rO   	__array__  s    zMultiIndex.__array__c             C  s   |   }| j|_|S )z0this is defined as a copy with the same identity)rh   _id)rL   rv   ry   rN   rN   rO   r     s    zMultiIndex.viewr   )keyr   c          
   C  s6   t | y| | dS  tttfk
r0   dS X d S )NTF)hashget_locLookupErrorr^   rk   )rL   r   rN   rN   rO   __contains__  s    
zMultiIndex.__contains__znp.dtypec             C  s
   t dS )NO)rI   rx   )rL   rN   rN   rO   rx     s    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| kpd| kpd| kS )NmixedstringunicoderN   )r|   rN   rN   rO   f  s    z0MultiIndex._is_memory_usage_qualified.<locals>.fc             3  s   | ]} |V  qd S )NrN   )r   r|   )r   rN   rO   r     s    z8MultiIndex._is_memory_usage_qualified.<locals>.<genexpr>)r   _inferred_type_levels)rL   rN   )r   rO   _is_memory_usage_qualified  s    z%MultiIndex._is_memory_usage_qualified)r   r   c             C  s
   |  |S )N)_nbytes)rL   r   rN   rN   rO   memory_usage  s    zMultiIndex.memory_usagec             C  s
   |  dS )z1return the number of bytes in the underlying dataF)r   )rL   rN   rN   rO   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   )r   rN   rO   r     s    z%MultiIndex._nbytes.<locals>.<genexpr>c             s  s   | ]}|j V  qd S )N)r   )r   r   rN   rN   rO   r     s    c             3  s   | ]}t | V  qd S )N)r   )r   r   )objsizerN   rO   r     s    )r   )sumrw   rM   r]   r   Zsizeof)rL   r   Zlevel_nbytesZlabel_nbytesZnames_nbytesry   rN   )r   r   rO   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  s   g | ]
}|j qS rN   )_formatter_func)r   r|   rN   rN   rO   r     s    z.MultiIndex._formatter_func.<locals>.<listcomp>c             s  s   | ]\}}||V  qd S )NrN   )r   funcvalrN   rN   rO   r     s    z-MultiIndex._formatter_func.<locals>.<genexpr>)rw   r   r   )rL   tupZformatter_funcsrN   rN   rO   r     s    zMultiIndex._formatter_funcnanc             K  s   g }g }xt | j| jD ]z\}}|jf d|i|}|dk}| r~t|}	|t}t	||}|j
jrnt| }|	||< |	| |	| qW t|dkrt|d |d  S t||| j| jdd}
|
jS d S )Nna_repr~   rE   r   F)rw   rM   r]   re   rg   )r   rw   rM   _format_native_typesr   rj   rZ   strrI   r   flags	writeableAssertionErrorrh   r4   takerB   r]   re   r   )rL   r   ra   r   rz   r|   r   Z
level_strsmaskZ	nan_indexmirN   rN   rO   r      s.    

zMultiIndex._format_native_typesr   zbool | NonezCallable | Nonez
str | None)r\   	formatterr   r]   spaceadjoinr   c               s  |d k	r|}t | dkrg S g }xt| j| jD ]\}	}
|d k	rD|n
t|	jj t |	dkr|	|
j|d}|
dk}|	 rt
j|td} ||< | }n fddt|	j|
D }|| q0W g }x`t|| jD ]P\}	}g }|r||d k	rt|ddnd	 |t
j|	td || qW |d kr@td
}|rd	}t|tsf|tjksft|dtjgkrz|}t|t||d}|rddlm} | }|j|f|  dS |S d S )Nr   )r   r~   )rx   c               s$   g | ]}t t|r n|d dqS ))	
)escape_chars)r>   r0   )r   r   )narN   rO   r   D  s   z%MultiIndex.format.<locals>.<listcomp>)r   r   r   )r    zdisplay.multi_sparseF)startsentinel)get_adjustmentr   )!rj   r   rw   rM   _get_na_reprx   r   r   formatr   rI   r   rY   tolistr   take_ndr   r   r]   r>   extendr   r   rf   r   r   r   sparsify_labelsrr   Zpandas.io.formats.formatr  r   split)rL   r\   r   r   r]   r   Zsparsifyr   Zstringified_levelsr   r   	formattedr   Zresult_levelsZlev_namer|   r  r  ZadjrN   )r   rO   r  "  sP    



zMultiIndex.formatc             C  s
   t | jS )N)r8   rp   )rL   rN   rN   rO   
_get_namesp  s    zMultiIndex._get_names)ri   c               s   |dk	rt |stdt|}|rb|dk	rDt|t|krDtd|dkrbt| jkrbtd|dkrvt j}n fdd|D }xDt||D ]6\}}|dk	rt|stt	 j
 d| j|< qW    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               s   g | ]}  |qS rN   )r   )r   r   )rL   rN   rO   r     s    z)MultiIndex._set_names.<locals>.<listcomp>z.name must be a hashable type)r'   rk   r{   rj   r   r   r   r$   r^   r   rQ   rp   r   )rL   r]   r|   ri   r   r\   rN   )rL   rO   rq   s  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   c             C  s   | j | }| j| }|d k	r@| j| |}||}|d d fS tj|dd\}}t|dkr|d dkr|dk}	tj||	 dd\}
}tjt||j	d}|
||	< d||	 < t|t|k r||}n|
 }|jr|j|dd}n
||}|||fS )NT)sortr   r~   )rx   )
fill_value)rM   rw   r   mapr   Z	factorizerj   rI   emptyrx   rh   Z_can_hold_na)rL   mapperr|   indexerlevel_indexZlevel_valuesZgrouperrM   uniquesr   Zok_codesrN   rN   rO   _get_grouper_for_level  s(    





z!MultiIndex._get_grouper_for_levelr   c             C  s   dS )Nr   rN   )rL   rN   rN   rO   inferred_type  s    zMultiIndex.inferred_typec          
   C  s   | j |}|dkr,t|s,td| dy| j |}W n tk
r } zt|sjtd| d|nf|dk r|| j7 }|dk r|| j }td| j d| d	|n&|| jkrtd| j d
|d  |W d d }~X Y nX |S )NrE   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 )r]   countr%   rk   r   KeyErrorr   
IndexError)rL   r|   r  errZ
orig_levelrN   rN   rO   r     s*    


zMultiIndex._get_level_numberc             C  s   dS )NTrN   )rL   rN   rN   rO   _has_complex_internals  s    z!MultiIndex._has_complex_internalsc               s   t dd  jD rdS tdd  jD rBtdd  jD S  fddttt jD }yt	
|}t|jS  tk
r   t jjS X dS )	zh
        return if the index is monotonic increasing (only equal or
        increasing) values.
        c             s  s   | ]}d |kV  qdS )r~   NrN   )r   r}   rN   rN   rO   r     s    z5MultiIndex.is_monotonic_increasing.<locals>.<genexpr>Fc             s  s   | ]}|j V  qd S )N)is_monotonic)r   r|   rN   rN   rO   r     s    c             S  s   g | ]}|j d ddqS )int64F)rh   )rZ   )r   r   rN   rN   rO   r     s    z6MultiIndex.is_monotonic_increasing.<locals>.<listcomp>c               s   g | ]}  |jqS rN   )r   r   )r   r   )rL   rN   rO   r     s    N)r   rM   allrw   libalgosis_lexsortedreversedr   rj   rI   lexsortr4   r  r^   r   )rL   r   Z
sort_orderrN   )rL   rO   is_monotonic_increasing  s     

z"MultiIndex.is_monotonic_increasingc             C  s   | ddd j S )zh
        return if the index is monotonic decreasing (only equal or
        decreasing) values.
        Nr~   )r%  )rL   rN   rN   rO   is_monotonic_decreasing'  s    z"MultiIndex.is_monotonic_decreasingz	list[str]c             C  s   dd | j D S )z7return a list of the inferred types, one for each levelc             S  s   g | ]
}|j qS rN   )r  )r   r   rN   rN   rO   r   3  s    z4MultiIndex._inferred_type_levels.<locals>.<listcomp>)rw   )rL   rN   rN   rO   r   0  s    z MultiIndex._inferred_type_levelsfirstc             C  s0   t dd | jD }t| j|ddd}t||S )Nc             s  s   | ]}t |V  qd S )N)rj   )r   r   rN   rN   rO   r   7  s    z(MultiIndex.duplicated.<locals>.<genexpr>F)r  Zxnull)r   rw   r;   rM   r   )rL   keepshapeZidsrN   rN   rO   r   5  s    zMultiIndex.duplicatedc             C  s   t ddS )z:
        fillna is not implemented for MultiIndex
        z"isna is not defined for MultiIndexN)NotImplementedError)rL   valueZdowncastrN   rN   rO   fillna@  s    zMultiIndex.fillnar   )howr   c               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~   rN   )r   r   rN   rN   rO   r   H  s    z%MultiIndex.dropna.<locals>.<listcomp>r   r   )rF   r   zinvalid how option: c               s   g | ]}|   qS rN   rN   )r   r   )r  rN   rO   r   P  s    )rM   )rM   rI   r   r   rk   r   )rL   r-  Znansrz   rN   )r  rO   dropnaF  s    zMultiIndex.dropnar4   )r|   uniquer   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\   )	rw   rM   rp   r   r/  r  r   Z	_na_valuer   )rL   r|   r/  r   r   r\   ZfilledrN   rN   rO   r   S  s    



zMultiIndex._get_level_valuesc             C  s   |  |}| |}|S )a  
        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).

        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')
        )r   r   )rL   r|   r   rN   rN   rO   get_level_valuesl  s     

zMultiIndex.get_level_valuesc               s.   |d krt   S | |}| j|ddS d S )NT)r|   r/  )superr/  r   r   )rL   r|   )	__class__rN   rO   r/    s    

zMultiIndex.unique)r   r   c               s   ddl m} |dk	rDt|s$tdt|t jkr>td|}n j}| fddt|t	t jD dd	}|r~ |_
|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.

        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   )r@   Nz1'name' must be a list / sequence of column names.z<'name' should have same length as number of levels on index.c               s(   i | ] \}}  ||d kr |n|qS )N)r   )r   Zlvlnamer|   )rL   rN   rO   r     s   z'MultiIndex.to_frame.<locals>.<dictcomp>F)rh   )r   r@   r'   r^   rj   rw   rk   r]   r   r   r   )rL   r   r\   r@   Z	idx_namesry   rN   )rL   rO   to_frame  s     2
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)Ztupleize_cols)r4   r   )rL   rN   rN   rO   to_flat_index  s    zMultiIndex.to_flat_indexc             C  s   dS )NFrN   )rL   rN   rN   rO   _is_all_dates  s    zMultiIndex._is_all_datesc             C  s   t jdtd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_lexsorted)rL   rN   rN   rO   r"    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   )rL   rN   rN   rO   r6    s     zMultiIndex._is_lexsortedc             C  s   t jdtdd | jS )NzxMultiIndex.is_lexsorted is deprecated as a public function, users should use MultiIndex.is_monotonic_increasing instead.r   )r   )r   r   r   r   )rL   rN   rN   rO   lexsort_depth3  s
    zMultiIndex.lexsort_depthc             C  s   | j dk	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)re   r   rM   r   )rL   rN   rN   rO   r   =  s    

zMultiIndex._lexsort_depthc          	   C  s   |   r| jr| S g }g }xt| j| jD ]r\}}|jsy| }W n tk
rX   Y n0X ||}t|}t	
|t|}t||}|| || q*W 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)r]   re   rg   )r6  r  r   rw   rM   argsortr^   r   r"   r   Zget_reverse_indexerrj   r   r  r   rB   r]   re   )rL   r   rz   r   r   r  rirN   rN   rO   _sort_levels_monotonicK  s,    "

z!MultiIndex._sort_levels_monotonicc             C  sd  g }g }d}xt | j| jD ]
\}}tt|d dkd d }tt|o\|d dk}t|t|| kr| 	 rt|t|krP d}t
|}|rt|dkd }||d dg |d|d g< tt|| }	tt|| |	|< |	| }|||d }|| || qW |  }
|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']])
        FrE   r   r~   TN)ri   )r   rw   rM   rI   r   Zbincountrr   rj   r0   r   r   r/  zerosaranger   r   r   ru   rn   ro   )rL   r   rz   changedr   r   r  Zhas_naZna_idxZcode_mappingry   rN   rN   rO   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)rw   rM   re   r]   N)r{   rw   rM   re   r]   ibaseZ
_new_Indexr   )rL   drN   rN   rO   
__reduce__  s
    zMultiIndex.__reduce__c               s   t  rjtj dd g }xFt| j| jD ]4\}}|  dkrL|tj q*|||    q*W t	|S d }t
 rtj td | j}n:t tr jd ks jdkr| j}nt trt   fdd| jD }t| j|| j|dd	S d S )
NT)Z
warn_floatr~   )rx   r   c               s   g | ]}|  qS rN   rN   )r   r   )r   rN   rO   r     s    z*MultiIndex.__getitem__.<locals>.<listcomp>F)rw   rM   r]   re   rg   )r)   comZcast_scalar_indexerr   rw   rM   r   rI   r   r   is_bool_indexerr   rf   re   r   slicestepr4   rB   r]   )rL   r   retvalr   r   re   rz   rN   )r   rO   __getitem__  s0    



zMultiIndex.__getitem__rD  )rL   slobjr   c               sL   d} j dk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               s   g | ]}|  qS rN   rN   )r   r   )rH  rN   rO   r     s    z-MultiIndex._getitem_slice.<locals>.<listcomp>F)rw   rM   r]   re   rg   )rE  re   rM   r   rw   rp   )rL   rH  re   rz   rN   )rH  rO   _getitem_slice  s    zMultiIndex._getitem_slicer   r   )rL   rF   
allow_fillr   c               s   t d| t  | || }d} fdd| jD }|r dk}| rg }	x(|D ] }
|
}|||< |	t| qXW |	}t	| j
|| jddS )NrN   r~   c               s   g | ]}|  qS rN   )r   )r   lab)indicesrN   rO   r   9  s    z#MultiIndex.take.<locals>.<listcomp>F)rw   rM   r]   rg   )nvZvalidate_taker"   Z_maybe_disallow_fillrM   r   r   rI   r   rB   rw   r]   )rL   rL  rF   rJ  r  ra   Zna_valueZtakenr   ZmaskedZ	new_labelZlabel_valuesrN   )rL  rO   r   (  s     	
zMultiIndex.takec          	     s   t |ttfs|g}tfdd|D r~g }x>tjD ]0  } fdd|D }||| q:W tj	|j
dS jftdd |D  }t|}ytj|j
dS  ttfk
r   t|S X dS )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 )N)r   rB   r   )r   o)rL   rN   rO   r   X  s    z$MultiIndex.append.<locals>.<genexpr>c               s   g | ]}|  qS rN   )r   )r   rN  )r   rN   rO   r   ]  s    z%MultiIndex.append.<locals>.<listcomp>)r]   c             s  s   | ]}|j V  qd S )N)r   )r   krN   rN   rO   r   a  s    N)r   r{   r   r   r   r   r   r   rB   r   r]   r   rI   r   r   r^   r  r4   )rL   otherr   labelZappendedZ	to_concatZ
new_tuplesrN   )r   rL   rO   r   H  s     

zMultiIndex.appendc             O  s   | j j||S )N)r   r8  )rL   r`   ra   rN   rN   rO   r8  j  s    zMultiIndex.argsortrepeat)repeatsr   c               s@   t dd|i t  t| j fdd| jD | j| jddS )NrN   rF   c               s&   g | ]}| tjtj qS rN   )r   rI   r   rZ   intprR  )r   r   )rS  rN   rO   r   v  s   z%MultiIndex.repeat.<locals>.<listcomp>F)rw   rM   r]   re   rg   )rM  Zvalidate_repeatr"   rB   rw   rM   r]   re   )rL   rS  rF   rN   )rS  rO   rR  m  s    
zMultiIndex.repeatraisec       	   	   C  s@  |dk	r|  |||S t|tjtfsTytj|tdd}W n tk
rR   Y nX g }x|D ]}y| 	|}t|t
r|| nt|tr|jdk	r|jnd}|t|j|j| nRt|r| jdkrtjdtdd | d }|| nd	t| }t|W q^ tk
r0   |d
kr, Y q^X 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
        NrY   )rx   rE   r   zYdropping on a non-lexsorted multi-index without a level parameter may impact performance.r   )r   zunsupported indexer of type ignore)_drop_from_levelr   rI   r   r4   rB  index_labels_to_arrayrx   rk   r   rr   r   rD  rE  r  r   r  stoprC  r   r   r   r   nonzeror   r   r  delete)	rL   rM   r|   errorsZindsr   locrE  msgrN   rN   rO   drop~  s<    






zMultiIndex.dropc       
      C  s   t |}| |}| j| }||}t|}d|t|d|dk@ < |jd | jd krld|t|d< ||dk }t	|dkr|dkrt
d| dt| j| | }	| |	 S )	NFr~   r   TrV  zlabels z not found in level)rB  rX  r   rw   get_indexerr0   rI   equalr)  rj   r  r   isinrM   )
rL   rM   r|   r\  r   r   r   Z	nan_codes	not_foundr   rN   rN   rO   rW    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')],
                   )
        F)rw   rM   r]   rg   )r{   rw   rM   r]   r   rB   )rL   r   jr   rz   	new_namesrN   rN   rO   	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               s   g | ]}  |qS rN   )r   )r   r   )rL   rN   rO   r   !	  s    z-MultiIndex.reorder_levels.<locals>.<listcomp>z2Length of order must be same as number of levels (z), got c               s   g | ]} j | qS rN   )rw   )r   r   )rL   rN   rO   r   '	  s    c               s   g | ]} j | qS rN   )rM   )r   r   )rL   rN   rO   r   (	  s    c               s   g | ]} j | qS rN   )r]   )r   r   )rL   rN   rO   r   )	  s    F)rw   rM   r]   rg   )rj   r   r   rB   )rL   orderr   rz   rf  rN   )rL   rO   reorder_levels	  s     zMultiIndex.reorder_levelsz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 )NrE   r   )rx   )rI   r<  rj   r   r   rx   )r   rN   rN   rO   cats8	  s    z/MultiIndex._get_codes_for_sorting.<locals>.catsc               s    g | ]}t j| |d dqS )T)Zordered)r1   Z
from_codes)r   r   )rj  rN   rO   r   ?	  s   z5MultiIndex._get_codes_for_sorting.<locals>.<listcomp>)rM   )rL   rN   )rj  rO   _get_codes_for_sorting/	  s    	
z!MultiIndex._get_codes_for_sortingztuple[MultiIndex, np.ndarray])	ascendingsort_remainingr   c       
        s\  t |ttfr|g}fdd|D }d}t |trht|t|ksLtdtfdd|D |dntj tjt	 fdd|D }t	fd	d|D }x(t
|d
dD ]} | | qW |r||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
            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               s   g | ]}  |qS rN   )r   )r   r   )rL   rN   rO   r   {	  s    z(MultiIndex.sortlevel.<locals>.<listcomp>Nz(level must have same length as ascendingc               s   g | ]} j | qS rN   )rM   )r   r   )rL   rN   rO   r   	  s    )Zordersc             3  s   | ]} | V  qd S )NrN   )r   r   )rM   rN   rO   r   	  s    z'MultiIndex.sortlevel.<locals>.<genexpr>c             3  s   | ]} | V  qd S )NrN   )r   r   )r)  rN   rO   r   	  s    T)reverser   F)compressr~   c               s   g | ]}|  qS rN   )r   )r   r   )r  rN   rO   r   	  s    )rM   rw   r]   re   rg   )r   r   rr   r{   rj   rk   r=   rM   r   r   sortedr_   r<   r"   rB   rw   r]   )
rL   r|   rl  rm  re   primaryZprimshpr   rz   r   rN   )rM   r  rL   r)  rO   	sortlevelC	  s@    6



zMultiIndex.sortlevelz$tuple[MultiIndex, np.ndarray | None]c             C  sz  t |d }|dk	r|dk	r$tdt|}t|dkrt|ts| j| }| }|	dd t
|jtjd|jdf|}nt|}| j||ddd	\}}	}
n:t|}| |rd}	n"| jr| j||||d
}	ntdt|ts<|	dkr| }nD|	dk r| |	}n*yt|}W n tk
r:   ||	fS X |rr|j| jkrr|j| jkrr|jdd}| j|_||	fS )a  
        Create index with target's values (move/add/delete values as necessary)

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

        r]   Nz)Fill method not supported if level passedr   freq)rx   rightF)r-  Z
keep_order)methodlimit	tolerancez'cannot handle a non-unique multi-index!)r   )hasattrr^   r?  Zensure_has_lenrj   r   r4   rw   Z_get_attributes_dictr_   r   Z_simple_newrI   r  rx   r6   Z_join_levelequalsr   ra  rk   rB   r   r   r   r   r]   rh   )rL   targetru  r|   rv  rw  Zpreserve_namesr   attrsr  _rN   rN   rO   reindex	  sF    

 

zMultiIndex.reindexc             C  s   t |rt|rt|d S )N)r$   r&   r   )rL   r   rN   rN   rO   _check_indexing_error	  s    z MultiIndex._check_indexing_errorc             C  s   | j d  S )zA
        Should integer key(s) be treated as positional?
        r   )rw   _should_fallback_to_positional)rL   rN   rN   rO   r  	  s    z)MultiIndex._should_fallback_to_positional)seriesc             C  sb   |j | }t|r|S t|dkr4| jdks4|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`
        rE   r   )r   r\   )r   r)   rj   r   maybe_droplevelsr   r\   Z__finalize__)rL   r  r]  r   
new_valuesr   Znew_serrN   rN   rO   _get_values_for_loc
  s    

zMultiIndex._get_values_for_locznp.ndarray | Nonec             C  s   d}t |rt|d ts| j|dd\}}|dkrLtjt | tjd}|S | jd |}|dk}|	 rt
||  dnt||rt
| d|S )a  
        Analogous to get_indexer when we are partial-indexing on our first level.

        Parameters
        ----------
        keyarr : Index, np.ndarray, or ExtensionArray
            Indexer to convert.

        Returns
        -------
        np.ndarray[intp] or None
        Nr   )r|   )rx   r~   z not in index)rj   r   r   r}  rI   r<  rT  rw   ra  r   r  r3   )rL   Zkeyarrr  r|  checkr   rN   rN   rO   _convert_listlike_indexer
  s    
z$MultiIndex._convert_listlike_indexerc             C  s   t |tr4| jd jr4|ftdft| jd   }t |trg }xHt|D ]<\}}t |tr~| j| jr~|t||d qL|| qLW t|}|S )z
        Translate any partial string timestamp matches in key, returning the
        new key.

        Only relevant for MultiIndex.
        r   NrE   )	r   r   rw   Z!_supports_partial_string_indexingrD  rj   r   r   r   )rL   r   Znew_keyr   	componentrN   rN   rO   '_get_partial_string_timestamp_match_key;
  s    

z2MultiIndex._get_partial_string_timestamp_match_key)rz  ru  rv  r   c          	   C  s   t |sttg S t|tshyt|}W n8 ttfk
rf   |d krbt	| j
j||||dS Y nX |dksx|dkr| jj|j
| j
||d}n| j|j
}t|S )N)ru  rv  rw  padZbackfill)rz  r   ru  rv  )rj   r"   rI   r   r   rB   r   r^   rk   r4   r   ra  r   Zget_indexer_with_fill)rL   rz  ru  rv  rw  r  rN   rN   rO   _get_indexerX
  s    


zMultiIndex._get_indexerzHashable | Sequence[Hashable])rQ  sidekindr   c             C  s   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}

        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.
        )r  )r   r   _partial_tup_index)rL   rQ  r  r  rN   rN   rO   get_slice_bound
  s    /
zMultiIndex.get_slice_boundc               s   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

        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.
        )r1  
slice_locs)rL   r  endrE  r  )r2  rN   rO   r  
  s    6zMultiIndex.slice_locsleftr   )r   c             C  s  t || jkr*tdt | d| j dt |}dt |  }}t|| j| j}x2t|D ]$\}\}}	}
|
|| }||	krt|s|	t	j
|gddstd| |	j||d}|d	kr|dkr|d
8 }||j||d S | |	|}t|tr||d
 k r|j}|j}q\||d
 k rL||j|d	d }||j|dd }q\t|trp|j}||j||d S ||j||d S q\W d S )NzKey length (z-) was greater than MultiIndex lexsort depth ()r   F)ZskipnazLevel type mismatch: )r  rt  rE   r  )rj   r   r   r   rw   rM   r   r0   Zis_type_compatibler   Zinfer_dtyper^   searchsorted_get_loc_single_level_indexr   rD  r  rY  )rL   r   r  nr  r  ZzippedrO  rK  r   Zlabssectionr]  r   rN   rN   rO   r  
  s4    zMultiIndex._partial_tup_indexr	   )r  r   r   c             C  s"   t |rt|rdS ||S d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~   N)r)   r0   r   )rL   r  r   rN   rN   rO   r    s    z&MultiIndex._get_loc_single_level_indexc               s  |dk	rt dt|  fdd}t|tsD j|dd}||S t|} j|k rntd| d j d	| jkr jr j	
|S  j}|d| ||d  }}|r ||n
dt f\}	}
|	|
krt||st|	|
S tjd
tdd tj|	|
tjd}x`t|t|D ]N\}} j| |   j| |k}| sT|| }t|st|qW t||
|	 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 possiblerf   )rx   FT)r   rI   r   rx   rT  r   Zmaybe_indices_to_slicerj   rD  r  fill)r]  r   )rL   rN   rO   _maybe_to_slice[  s    

z+MultiIndex.get_loc.<locals>._maybe_to_slicer   )r|   zKey length (z) exceeds index depth (r  z3indexing past lexsort depth may impact performance.
   )r   )rx   )r*  r   r   r   _get_level_indexerrj   r   r  r   r   r   r   r  rD  r   r   r   rI   r<  rT  r   rM   r  rw   r   )rL   r   ru  r  r]  Zkeylenr   Zlead_keyZ
follow_keyr  rY  rO  r   rN   )rL   rO   r   )  sD    *

 


zMultiIndex.get_loc)
drop_levelc               s<   t |ttfs |}n fdd|D } j|||d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               s   g | ]}  |qS rN   )r   )r   r   )rL   rN   rO   r     s    z,MultiIndex.get_loc_level.<locals>.<listcomp>)r|   r  )r   r{   r   r   _get_loc_level)rL   r   r|   r  rN   )rL   rO   get_loc_level  s    &zMultiIndex.get_loc_levelzint | list[int])r|   r  c          
     s  ddfddt |ttfrtt|kr8tdd}xdt|D ]V\}}j||d\}}t |trtj	tt
d}	d	|	|< |	}|dkr|n||@ }qHW ||| fS t trtt tr|d
kry8jd
 krj|d}
|
d
g }|
|fS W n ttfk
r,   Y nX tdd D sd fdd	}tjkrjryjdfS  tk
r } zt|W dd}~X Y nX n|S nd}
xtD ]\}}t |ts j||d}t |tr|jd
kr |jtkr tdd}n|}t |trJ|tddkrBqnt|
dkrZ|}
n|
|M }
qW |
dkr|tdd}
fddttD }|
|
| fS n j|d}
|
|
|g fS dS )zX
        get_loc_level but with `level` known to be positional, not name-based.
        rf   )r  c          	     sX   |s |  S  |   }}x:t |ddD ]*}y||g}W q& tk
rN   |S X q&W |S )NT)rn  )rp  _drop_level_numbersrk   )r  rw   r  Z
orig_indexr   r   )rL   rN   rO   maybe_mi_droplevels  s    
z6MultiIndex._get_loc_level.<locals>.maybe_mi_droplevelsz:Key for location must have same length as number of levelsN)r|   )rx   Tr   c             s  s   | ]}t |tV  qd S )N)r   rD  )r   rO  rN   rN   rO   r     s    z,MultiIndex._get_loc_level.<locals>.<genexpr>c               s<   |d kr  } fddtt D }|||fS )Nc               s"   g | ]} | t d d kr|qS )N)rD  )r   r   )r   rN   rO   r     s    zHMultiIndex._get_loc_level.<locals>.partial_selection.<locals>.<listcomp>)r   r   rj   )r   r  ilevels)r  r  rL   )r   rO   partial_selection  s    
z4MultiIndex._get_loc_level.<locals>.partial_selectionc               s"   g | ]} | t d d kr|qS )N)rD  )r   r   )r   rN   rO   r   %  s    z-MultiIndex._get_loc_level.<locals>.<listcomp>)N)r   r   r{   rj   r   r   r  rD  rI   r;  rf   rw   r  r^   r   r   r   r   r   r   r  r   r  rY  r   )rL   r   r|   r  ry   r   rO  r]  r   r   r  r  er   Zk_indexr  rN   )r  r   r  rL   rO   r    sj    





zMultiIndex._get_loc_level)r|   c             C  s  | j | }| j| }||fdd}t|trRy^|jd k	rH||j}nd}|jd k	rd||j}n t|trxt|}nt|d }|j}	W n2 t	k
r   |
|j|j|j }}|j}	Y nX t|tst|trt|d|}t|d|}||||	S |dks| jdks|	d k	r(|||d |	S |j|dd}
|j|d	d}t|
||	S n| ||}|dkst| jdkrtj||ktd
d}| st	||S t|tr|j}|j}n|j|dd}|j|d	d}||krt	|t||S d S )Nc       
      S  s   |d k	r"|dk r"|d | d  } }t | ||}|d k	rt|t|krddlm} ||}|t|}|t||	 d }|
|}	t |	}	n,t jt|td}	d|	t j||t|jd< |	S )Nr   rE   )rA   )rx   T)Zassume_unique)rI   r<  rj   r   rA   r   r"   r4   rc  rZ  r  r   r;  rf   Zin1dr   )
r  rY  rE  r  rM   rrA   r  ry   mrN   rN   rO   convert_indexer4  s    
z6MultiIndex._get_level_indexer.<locals>.convert_indexerr   rE   r  rY  r  )r  rt  F)rx   rh   )rw   rM   r   rD  r  r   rY  rj   rE  r  Zslice_indexerr   r   r  r  rI   r   rf   r   )rL   r   r|   r  r  r   r  r  rY  rE  r   re  r   Zlocsr  rN   rN   rO   r  +  sP    

#




 

zMultiIndex._get_level_indexerc          
     s  dd t t|D }|r@|d | jkr@td| d| j t|  d}dd fd	d
}dddd fdd}x<t |D ].\}}t|rt|}|||||d}qt	|rFd}xX|D ]P}	y2|| j
|	||d}
|dkr|
n|j|
dd}W q tk
r   wY qX qW |dk	r4||||d}ntjg tjdS qt|rb|d||d}qt|tr||| j
|||d||d}q||| j||ddd ||d}qW |dkrtjg tjdS t|tstt|| ||}|j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 rN   rN   )r   r   srN   rN   rO   r     s    z'MultiIndex.get_locs.<locals>.<listcomp>r~   zIMultiIndex slicing requires the index to be lexsorted: slicing on levels z, lexsort depth Nr9   )r   c               s`   t | tr.tj td}d|| < | d } n*t| rXt|  krLt	d|  d } t
| S )N)rx   Tr   zLcannot index with a boolean indexer that is not the same length as the index)r   rD  rI   r;  rf   rZ  rB  rC  rj   rk   r9   )r  r  )r  rN   rO   _convert_to_indexer  s    

z0MultiIndex.get_locs.<locals>._convert_to_indexerzIndex | Noner4   )idxrr  r   c               sJ   |d krt t }| d kr"|S || }|jrF| jsF|jsFt||S )N)r4   rI   r<  intersectionr  r  )r  r  r   Zindexer_intersection)r  rN   rO   _update_indexer  s    
z,MultiIndex.get_locs.<locals>._update_indexer)r  r   )r|   r  F)r  )rx   )r|   r  r   )r   rB  Zis_true_slicesr   r   rj   rC  rI   r   r'   r  unionr  r   r  Zis_null_slicer   rD  r  r9   r   r   _reorder_indexerr   )rL   seqZtrue_slicesr  r  r  r   rO  Zindexersr   ZidxrsrN   )r  rO   get_locs  sX    $







zMultiIndex.get_locsz,tuple[Scalar | Iterable | AnyArrayLike, ...]r9   )r  r  r   c             C  s  |   rd}x|t|D ]p\}}t|rd|s| j| |}||dk }|dd |dd k }qt|tr|jdk	r|jdk rd}qW |s|S t	| }d}xBt|D ]4\}}t
|r|g}t|rt|| }	nt|rZt|}tjt	| j| tjdt	| j|  }
| j| |}||dk }tt	||
|< |
| j| |  }	n|t|tr|jdk	r|jdk rt|| | }	nDt|tr|jdkr|jdkrt|f| }	nt|| }	|	f| }qW t|}|| S )	aq  
        Reorder an indexer of a MultiIndex (self) so that the label are in the
        same order as given in seq

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

        Returns
        -------
        indexer : a sorted Int64Index indexer of self ordered as seq
        Fr   Nr~   rE   TrN   )rx   )r6  r   r'   rw   ra  r   r   rD  rE  rj   r)   rB  rC  rI   r<  r   r/  Zonesr   rM   r  rY  r$  )rL   r  r  Z	need_sortr   rO  Zk_codesr  keysZ	new_orderZkey_order_mapZlevel_indexerindrN   rN   rO   r  &  sF    


$$
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 rN   rN   )r   r   )r  rt  rN   rO   r     s    z'MultiIndex.truncate.<locals>.<listcomp>F)rw   rM   r]   rg   )rk   rw   r  r{   rM   rB   rp   )rL   beforeafterr   re  r   rz   rN   )r  rt  rO   truncaten  s    
zMultiIndex.truncaterY   )rP  r   c       	      C  s2  |  |rdS t|tsdS t| t|kr0dS t|tsV| |sHdS t| j|jS | j|jkrfdS xt	| jD ]}| j
| }|j
| }|dk}|dk}t||sdS ||  }| j| j|}||  }|j| j|}t|dkrt|dkrqrt|tjs||s*dS qrt||srdS qrW d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   r4   rj   rB   Z_should_comparer/   r   r   r   rM   rI   Zarray_equalrw   r   r   ry  )	rL   rP  r   Z
self_codesZother_codesZ	self_maskZ
other_maskZself_valuesZother_valuesrN   rN   rO   ry    s>    	








zMultiIndex.equalsc             C  sB   | j |j krdS x,t| j D ]}| j| |j| sdS qW dS )zT
        Return True if the levels of both MultiIndex objects are the same

        FT)r   r   rw   ry  )rL   rP  r   rN   rN   rO   equal_levels  s    zMultiIndex.equal_levelsc               s   |  |\}}tdd | jD r6tdd | jD sB| jsB|jrRt ||}n$|jjtdd}t	j
| j|g|d}tjt| d|dS )	Nc             s  s   | ]}d |kV  qdS )r~   NrN   )r   r}   rN   rN   rO   r     s    z$MultiIndex._union.<locals>.<genexpr>c             s  s   | ]}d |kV  qdS )r~   NrN   )r   r}   rN   rN   rO   r     s    F)rh   )r  r   )re   r]   )_convert_can_do_setopr   rM   Zhas_duplicatesr1  _unionr   rZ   rY   r   Zfast_unique_multiplerB   r   r   )rL   rP  r  result_namesry   Zrvals)r2  rN   rO   r    s    zMultiIndex._unionr   )rx   r   c             C  s   t |S )N)r(   )rL   rx   rN   rN   rO   _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_namesr]   rename)rL   rP  r]   rN   rN   rO   _get_reconciled_name_object  s    


z&MultiIndex._get_reconciled_name_objectc             C  sf   t | jt |jkr$dgt | j S g }x8t| j|jD ]&\}}||krT|| q8|d q8W |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)rj   r]   r   r   )rL   rP  r]   a_nameZb_namerN   rN   rO   r    s    zMultiIndex._maybe_match_namesc             C  sL   |  |\}}t|dkr4t| jg g| j |ddS tjt| d|dS d S )Nr   F)rw   rM   r]   rg   )re   r]   )r  rj   rB   rw   r   r   r   )rL   rP  ry   r  rN   rN   rO   _wrap_intersection_result  s    
z$MultiIndex._wrap_intersection_resultc               s\   |  |\}}t ||}t|dkrHtg g| j g g| j |ddS tj|d|dS d S )Nr   F)rw   rM   r]   rg   )re   r]   )r  r1  _differencerj   rB   r   r   )rL   rP  r  r  
difference)r2  rN   rO   r    s    

zMultiIndex._differencec          
   C  s   | j }t|tszt|dkr.| d d | j fS d}ytj|| j d}W q ttfk
rv } zt||W d d }~X Y qX n
t| |}||fS )Nr   z.other must be a MultiIndex or a list of tuples)r]   )	r]   r   r4   rj   rB   r   rk   r^   r7   )rL   rP  r  r^  r  rN   rN   rO   r  (  s    

z MultiIndex._convert_can_do_setop)rh   c             C  sD   t |}t|rd}t|n"t|s0tdn|dkr@|  S | S )Nz3> 1 ndim Categorical are not supported at this timezISetting a MultiIndex dtype to anything other than object is not supportedT)r*   r#   r*  r(   r^   r   )rL   rx   rh   r^  rN   rN   rO   rZ   >  s    
zMultiIndex.astypec             C  s:   t |ts |fd| jd   }nt|| jkr6td|S )N)r   rE   z0Item must have length equal to number of levels.)r   r   r   rj   rk   )rL   itemrN   rN   rO   _validate_fill_valueM  s
    
zMultiIndex._validate_fill_value)r]  r   c       	      C  s   |  |}g }g }xht|| j| jD ]T\}}}||krLt|}|||}n
||}|| |tt	||| q$W 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
        F)rw   rM   r]   rg   )r  r   rw   rM   rj   insertr   r   rI   r!   rB   r]   )	rL   r]  r  r   rz   rO  r|   r   Zlev_locrN   rN   rO   r  V  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 rN   )rI   r[  )r   r   )r]  rN   rO   r     s    z%MultiIndex.delete.<locals>.<listcomp>F)rw   rM   r]   rg   )rM   rB   rw   r]   )rL   r]  rz   rN   )r]  rO   r[  y  s    zMultiIndex.deletec             C  sh   |d kr(t j|| jdj}t| j|S | |}| |}|jdkrZt	j
t|t	jdS ||S d S )N)r]   r   )rx   )rB   r   r]   r   r   rc  r   r0  sizerI   r;  rj   Zbool_)rL   r   r|   numZlevsrN   rN   rO   rc    s    


zMultiIndex.isinzMultiIndex | None)r   r   c               s   t  j|||dS )N)r]   r|   r   )r1  	set_names)rL   r]   r|   r   )r2  rN   rO   r    s    zMultiIndex.set_namesz
str | bool)r(  r   c               s   t  j|dS )N)r(  )r1  drop_duplicates)rL   r(  )r2  rN   rO   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____inv__)NNNNNFNT)NN)NN)NN)NFTF)NNT)NFTF)NNT)NNNNFN)N)N)F)F)r   )NNNFr   NT)NT)r'  )NN)r   )F)N)TN)r   TN)N)NrU  )rU  )r`  r~   )r   TT)NNNN)NNN)N)NNNN)r  )N)r   T)r   T)r   N)NN)T)N)NF)r'  )rQ   rR   rS   rT   r4   Z_hidden_attrs	frozensetZ_typr8   rp   r   rt   Z_comparables__annotations__rl   r   rs   classmethodr   r   r   rd   r   r   r   r   r   propertyr   r   r   r   rw   rn   r   r   r   r   rM   ro   r   r   r   r   r   r   rh   r   r   r   rx   r   r   r   r   r   r   r  r  rq   r]   r  r  r   r  r%  r&  r   r   Z_duplicatedr,  r.  r   r0  r/  r3  r4  r5  r"  r6  r7  r   r:  r>  rA  rG  rI  r   r5   _index_doc_kwargsr   r   r8  rR  r_  rW  rg  ri  rk  rr  r}  r~  r  r  r  r  r  r  r  r  r  r   r  r  r  r  r  r  ry  r  r  r  r  r  r  r  r  rZ   r  r  r[  rc  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__rN   rN   )r2  rO   rB      s~  
L       &>A =;A   #o   R     O	$      F;%	$M	"
CZ"  "6:.lF#   $28&p,fo H":	#""




















zlist[np.ndarray]rr   )rM   r   r   c             C  s>   dd | D }x*t |ddD ]}t|d| r|S qW dS )zJCount depth (up to a maximum of `nlevels`) with which codes are lexsorted.c             S  s   g | ]}t |qS rN   )r!   )r   r   rN   rN   rO   r     s    z"_lexsort_depth.<locals>.<listcomp>r   r~   N)r   r!  r"  )rM   r   Zint64_codesrO  rN   rN   rO   r     s
    r   r   )r  c             C  s   t t|  }t| }|d |d  }|| }x||d d  D ]}g }xrtt||D ]`\}	\}
}|	|d kr|| || P |
|kr|| qV|||	d   || P qVW |}q>W t t| S )NrE   )r{   r   rj   r   r   r  )Z
label_listr  r  ZpivotedrO  ry   prevcurZ
sparse_curr   ptrN   rN   rO   r	    s$    


r	  r   )r   c             C  s   t jdt jdi| dS )NZNaTNaN)rI   Z
datetime64Ztimedelta64get)rx   rN   rN   rO   r    s    r  r4   )r   r   c          	   C  sn   | }t |trDxZ|D ]*}y| dg} W q tk
r<   |S X qW n&y| dg} W n tk
rh   Y nX | S )z
    Attempt to drop level or levels from the given index.

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

    Returns
    -------
    Index
    r   )r   r   r  rk   )r   r   Zoriginal_indexr|  rN   rN   rO   r    s    

r  Frf   z
np.ndarray)rh   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    rh   r   r   )Z
array_like
categoriesrh   rN   rN   rO   r     s
    
r   )arrnamec             C  s   | dk	rNt | sNt |s&t| dt |d r@t| d| g} |g}n2| dks^t | rt |rrt |d st| 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'   r^   )r|   r   r  rN   rN   rO   r     s    r   )r   r   )F)y
__future__r   	functoolsr   sysr   typingr   r   r   r   r	   r
   r   r   r   r   r   numpyrI   Zpandas._configr   Zpandas._libsr   r!  r   rU   r   Zpandas._libs.hashtabler   Zpandas._typingr   r   r   r   Zpandas.compat.numpyr   rM  Zpandas.errorsr   r   r   Zpandas.util._decoratorsr   r   r   r   Zpandas.core.dtypes.castr    Zpandas.core.dtypes.commonr!   r"   r#   r$   r%   r&   r'   r(   r)   r*   Zpandas.core.dtypes.dtypesr+   Zpandas.core.dtypes.genericr,   r-   r.   Zpandas.core.dtypes.missingr/   r0   Zpandas.core.algorithmscoreZ
algorithmsZpandas.core.arraysr1   Zpandas.core.arrays.categoricalr2   Zpandas.core.commoncommonrB  Zpandas.core.indexersr3   Zpandas.core.indexes.baseZindexesbaser?  r4   r5   r6   r7   Zpandas.core.indexes.frozenr8   Zpandas.core.indexes.numericr9   Zpandas.core.ops.invalidr:   Zpandas.core.sortingr;   r<   r=   Zpandas.io.formats.printingr>   r   r?   r@   rA   dictr  updateZBaseMultiIndexCodesEnginerV   rD   r[   rX   rd   rB   r   r	  r  r  r   r   rN   rN   rN   rO   <module>   s   00
')                            		