
    Pi                       d 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 ddlZddlmZ ddlmZmZmZmZmZmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddl m!Z! ddl"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-m.Z. ddl/m0Z0m1Z1m2Z2 ddl3m4Z4 ddl5m6Z6 ddl7m8Z8 ddl9m:Z:m;Z; erddl<m=Z=m>Z> ddlm?Z?m@Z@mAZAmBZB ddlCmDZDmEZEmFZF  G d de4          ZG G d d          ZH G d dee                   ZI G d de6          ZJdS ) z.
Base and utility classes for pandas objects.
    )annotations)TYPE_CHECKINGAnyGenericLiteralSelfcastfinaloverloadN)lib)AxisIntDtypeObj
IndexLabelNDFrameTShapenpt)PYPY)functionAbstractMethodError)cache_readonly)can_hold_element)is_object_dtype	is_scalar)ExtensionDtype)ABCDataFrameABCIndexABCMultiIndex	ABCSeries)isnaremove_na_arraylike)
algorithmsnanopsops)DirNamesMixin)OpsMixin)ExtensionArray)ensure_wrapped_if_datetimelikeextract_array)HashableIterator)DropKeepNumpySorterNumpyValueArrayLikeScalarLike_co)	DataFrameIndexSeriesc                  Z     e Zd ZU dZded<   edd            ZddZdddZd fdZ	 xZ
S )PandasObjectz0
    Base class for various pandas objects.
    zdict[str, Any]_cachereturn
type[Self]c                     t          |           S )zK
        Class constructor (for this class it's just `__class__`).
        )typeselfs    d/home/jaya/work/projects/VOICE-AGENT/VIET/agent-env/lib/python3.11/site-packages/pandas/core/base.py_constructorzPandasObject._constructor\   s    
 Dzz    strc                6    t                               |           S )zI
        Return a string representation for a particular object.
        )object__repr__r:   s    r<   rB   zPandasObject.__repr__c   s    
 t$$$r>   Nkey
str | NoneNonec                    t          | d          sdS || j                                         dS | j                            |d           dS )zV
        Reset cached properties. If ``key`` is passed, only clears that key.
        r5   N)hasattrr5   clearpop)r;   rC   s     r<   _reset_cachezPandasObject._reset_cachej   sV     tX&& 	F;KKOOC&&&&&r>   intc                    t          | dd          }|r> |d          }t          t          |          r|n|                                          S t	                                                      S )zx
        Generates the total memory usage for an object that returns
        either a value or Series of values
        memory_usageNTdeep)getattrrK   r   sumsuper
__sizeof__)r;   rM   mem	__class__s      r<   rS   zPandasObject.__sizeof__u   sm    
 t^T:: 	=,D)))Cinn;ss#''))<<< ww!!###r>   )r6   r7   )r6   r?   N)rC   rD   r6   rE   r6   rK   )__name__
__module____qualname____doc____annotations__propertyr=   rB   rJ   rS   __classcell__)rU   s   @r<   r4   r4   T   s          
    X% % % %	' 	' 	' 	' 	'$ $ $ $ $ $ $ $ $ $r>   r4   c                  "    e Zd ZdZd	dZd
dZdS )NoNewAttributesMixina  
    Mixin which prevents adding new attributes.

    Prevents additional attributes via xxx.attribute = "something" after a
    call to `self.__freeze()`. Mainly used to prevent the user from using
    wrong attributes on an accessor (`Series.cat/.str/.dt`).

    If you really want to add a new attribute at a later time, you need to use
    `object.__setattr__(self, key, value)`.
    r6   rE   c                >    t                               | dd           dS )z9
        Prevents setting additional attributes.
        __frozenTN)rA   __setattr__r:   s    r<   _freezezNoNewAttributesMixin._freeze   s"     	4T22222r>   rC   r?   c                    t          | dd          r@|dk    s:|t          |           j        v s$t          | |d           t          d| d          t                              | ||           d S )Nrb   Fr5   z"You cannot add any new attribute '')rP   r9   __dict__AttributeErrorrA   rc   )r;   rC   values      r<   rc   z NoNewAttributesMixin.__setattr__   s     4U++ 	N8OOd4jj)))tS$''3 !Lc!L!L!LMMM4e,,,,,r>   N)r6   rE   )rC   r?   r6   rE   )rX   rY   rZ   r[   rd   rc    r>   r<   r`   r`      sF        	 	3 3 3 3- - - - - -r>   r`   c                     e Zd ZU dZded<   dZded<   ded<   d	d
gZ ee          Ze	e
d                         Zed             Ze	edd                        Ze	ed                         Zd ZdddZe	dd            Zd ZeZdS )SelectionMixinz
    mixin implementing the selection & aggregation interface on a group-like
    object sub-classes need to define: obj, exclusions
    r   objNzIndexLabel | None
_selectionzfrozenset[Hashable]
exclusionsr5   __setstate__c                    t          | j        t          t          t          t
          t          j        f          s| j        gS | j        S rV   )
isinstancern   listtupler   r   npndarrayr:   s    r<   _selection_listzSelectionMixin._selection_list   s?     OdE9h
K
 
 	% O$$r>   c                v    | j         t          | j        t                    r| j        S | j        | j                  S rV   )rn   rr   rm   r   r:   s    r<   _selected_objzSelectionMixin._selected_obj   s1    ?"j9&E&E"8O8DO,,r>   r6   rK   c                    | j         j        S rV   )ry   ndimr:   s    r<   r{   zSelectionMixin.ndim   s     !&&r>   c                    t          | j        t                    r| j        S | j        | j        | j                 S t          | j                  dk    r"| j                            | j        dd          S | j        S )Nr      T)axis
only_slice)rr   rm   r   rn   rw   lenro   
_drop_axisr:   s    r<   _obj_with_exclusionsz#SelectionMixin._obj_with_exclusions   st     dh	** 	8O?&8D011t!##
 8&&tQ4&PPP8Or>   c                   | j         t          d| j          d          t          |t          t          t
          t          t          j        f          rt          | j
        j                            |                    t          t          |                    k    r`t          t          |                              | j
        j                            }t          dt!          |          dd                    |                     t          |          d          S || j
        vrt          d|           | j
        |         j        }|                     ||          S )	Nz
Column(s) z already selectedzColumns not found: r}      )r{   zColumn not found: )rn   
IndexErrorrr   rs   rt   r   r   ru   rv   r   rm   columnsintersectionset
differenceKeyErrorr?   _gotitemr{   )r;   rC   bad_keysr{   s       r<   __getitem__zSelectionMixin.__getitem__   s)   ?&L$/LLLMMMcD%HbjIJJ 
	148#005566#c#hh--GGC 3 3DH4D E EFFJS]]1R45HJJKKK==c=333 $(""9C99:::8C=%D==4=000r>   r{   c                     t          |           )a  
        sub-classes to define
        return a sliced object

        Parameters
        ----------
        key : str / list of selections
        ndim : {1, 2}
            requested ndim of result
        subset : object, default None
            subset to act on
        r   )r;   rC   r{   subsets       r<   r   zSelectionMixin._gotitem   s     "$'''r>   r   Series | DataFramec                    d}|j         dk    r/t          j        |          r||v st          j        |          r|}n,|j         dk    r!t          j        |          r||j        k    r|}|S )zO
        Infer the `selection` to pass to our constructor in _gotitem.
        Nr   r}   )r{   r   r   is_list_likename)r;   rC   r   	selections       r<   _infer_selectionzSelectionMixin._infer_selection   sz     	;!]3 $'6MMc6Fs6K6KMII[A#-"4"49K9KIr>   c                     t          |           rV   r   )r;   funcargskwargss       r<   	aggregatezSelectionMixin.aggregate  s    !$'''r>   rW   rV   )r{   rK   )r   r   )rX   rY   rZ   r[   r\   rn   _internal_namesr   _internal_names_setr
   r]   rw   r   ry   r{   r   r   r   r   r   aggrj   r>   r<   rl   rl      sG         
 MMM$(J((((####0O#o..
  X U - - ^- ' ' ' ^ U'   ^ U 1 1 1 ( ( ( ( (    U( ( ( CCCr>   rl   c                     e Zd ZU dZdZ edg          Zded<   edZd            Z	ed[d
            Z
ed\d            Z eed          Zed]d            Zd^dZed^d            Zed             Zed^d            Zed^d            Zed_d            Zddej        fd`d"Zeedad#                        Z	 dbdcd(Z	 dbdcd)Zddd+ZeZded-Zedad.            Zedfd/            Z 	 	 	 	 	 dgdhd5Z!d6 Z"edidjd7            Z#edad8            Z$edad9            Z%edad:            Z&edkdld<            Z'	 	 dmdnd?Z(e)	 	 dodpdH            Z*e)	 	 dodqdK            Z*	 	 drdsdPZ*dQdRdtdUZ+edudvdW            Z,dX Z-dY Z.dS )wIndexOpsMixinzS
    Common ops mixin to support a unified interface / docs for Series / Index
    i  tolistzfrozenset[str]_hidden_attrsr6   r   c                     t          |           rV   r   r:   s    r<   dtypezIndexOpsMixin.dtype       "$'''r>   ExtensionArray | np.ndarrayc                     t          |           rV   r   r:   s    r<   _valueszIndexOpsMixin._values  r   r>   r   c                0    t          j        ||           | S )zw
        Return the transpose, which is by definition self.

        Returns
        -------
        %(klass)s
        )nvvalidate_transpose)r;   r   r   s      r<   	transposezIndexOpsMixin.transpose!  s     	dF+++r>   a:  
        Return the transpose, which is by definition self.

        See Also
        --------
        Index : Immutable sequence used for indexing and alignment.

        Examples
        --------
        For Series:

        >>> s = pd.Series(['Ant', 'Bear', 'Cow'])
        >>> s
        0     Ant
        1    Bear
        2     Cow
        dtype: str
        >>> s.T
        0     Ant
        1    Bear
        2     Cow
        dtype: str

        For Index:

        >>> idx = pd.Index([1, 2, 3])
        >>> idx.T
        Index([1, 2, 3], dtype='int64')
        )docr   c                    | j         j        S )a  
        Return a tuple of the shape of the underlying data.

        See Also
        --------
        Series.ndim : Number of dimensions of the underlying data.
        Series.size : Return the number of elements in the underlying data.
        Series.nbytes : Return the number of bytes in the underlying data.

        Examples
        --------
        >>> s = pd.Series([1, 2, 3])
        >>> s.shape
        (3,)
        )r   shaper:   s    r<   r   zIndexOpsMixin.shapeN  s    " |!!r>   rK   c                     t          |           rV   r   r:   s    r<   __len__zIndexOpsMixin.__len__a  s    !$'''r>   c                    dS )a   
        Number of dimensions of the underlying data, by definition 1.

        See Also
        --------
        Series.size: Return the number of elements in the underlying data.
        Series.shape: Return a tuple of the shape of the underlying data.
        Series.dtype: Return the dtype object of the underlying data.
        Series.values: Return Series as ndarray or ndarray-like depending on the dtype.

        Examples
        --------
        >>> s = pd.Series(["Ant", "Bear", "Cow"])
        >>> s
        0     Ant
        1    Bear
        2     Cow
        dtype: str
        >>> s.ndim
        1

        For Index:

        >>> idx = pd.Index([1, 2, 3])
        >>> idx
        Index([1, 2, 3], dtype='int64')
        >>> idx.ndim
        1
        r}   rj   r:   s    r<   r{   zIndexOpsMixin.ndimh  s	    > qr>   c                ~    t          |           dk    rt          t          |                     S t          d          )a  
        Return the first element of the underlying data as a Python scalar.

        Returns
        -------
        scalar
            The first element of Series or Index.

        Raises
        ------
        ValueError
            If the data is not length = 1.

        See Also
        --------
        Index.values : Returns an array representing the data in the Index.
        Series.head : Returns the first `n` rows.

        Examples
        --------
        >>> s = pd.Series([1])
        >>> s.item()
        1

        For an index:

        >>> s = pd.Series([1], index=["a"])
        >>> s.index.item()
        'a'
        r}   z6can only convert an array of size 1 to a Python scalar)r   nextiter
ValueErrorr:   s    r<   itemzIndexOpsMixin.item  s7    @ t99>>T

###QRRRr>   c                    | j         j        S )al  
        Return the number of bytes in the underlying data.

        See Also
        --------
        Series.ndim : Number of dimensions of the underlying data.
        Series.size : Return the number of elements in the underlying data.

        Examples
        --------
        For Series:

        >>> s = pd.Series(["Ant", "Bear", "Cow"])
        >>> s
        0     Ant
        1    Bear
        2     Cow
        dtype: str
        >>> s.nbytes
        34

        For Index:

        >>> idx = pd.Index([1, 2, 3])
        >>> idx
        Index([1, 2, 3], dtype='int64')
        >>> idx.nbytes
        24
        )r   nbytesr:   s    r<   r   zIndexOpsMixin.nbytes  s    > |""r>   c                *    t          | j                  S )a  
        Return the number of elements in the underlying data.

        See Also
        --------
        Series.ndim: Number of dimensions of the underlying data, by definition 1.
        Series.shape: Return a tuple of the shape of the underlying data.
        Series.dtype: Return the dtype object of the underlying data.
        Series.values: Return Series as ndarray or ndarray-like depending on the dtype.

        Examples
        --------
        For Series:

        >>> s = pd.Series(["Ant", "Bear", "Cow"])
        >>> s
        0     Ant
        1    Bear
        2     Cow
        dtype: str
        >>> s.size
        3

        For Index:

        >>> idx = pd.Index([1, 2, 3])
        >>> idx
        Index([1, 2, 3], dtype='int64')
        >>> idx.size
        3
        )r   r   r:   s    r<   sizezIndexOpsMixin.size  s    B 4<   r>   r'   c                     t          |           )ae	  
        The ExtensionArray of the data backing this Series or Index.

        This property provides direct access to the underlying array data of a
        Series or Index without requiring conversion to a NumPy array. It
        returns an ExtensionArray, which is the native storage format for
        pandas extension dtypes.

        Returns
        -------
        ExtensionArray
            An ExtensionArray of the values stored within. For extension
            types, this is the actual array. For NumPy native types, this
            is a thin (no copy) wrapper around :class:`numpy.ndarray`.

            ``.array`` differs from ``.values``, which may require converting
            the data to a different form.

        See Also
        --------
        Index.to_numpy : Similar method that always returns a NumPy array.
        Series.to_numpy : Similar method that always returns a NumPy array.

        Notes
        -----
        This table lays out the different array types for each extension
        dtype within pandas.

        ================== =============================
        dtype              array type
        ================== =============================
        category           Categorical
        period             PeriodArray
        interval           IntervalArray
        IntegerNA          IntegerArray
        string             StringArray
        boolean            BooleanArray
        datetime64[ns, tz] DatetimeArray
        ================== =============================

        For any 3rd-party extension types, the array type will be an
        ExtensionArray.

        For all remaining dtypes ``.array`` will be a
        :class:`arrays.NumpyExtensionArray` wrapping the actual ndarray
        stored within. If you absolutely need a NumPy array (possibly with
        copying / coercing data), then use :meth:`Series.to_numpy` instead.

        Examples
        --------
        For regular NumPy types like int, and float, a NumpyExtensionArray
        is returned.

        >>> pd.Series([1, 2, 3]).array
        <NumpyExtensionArray>
        [1, 2, 3]
        Length: 3, dtype: int64

        For extension types, like Categorical, the actual ExtensionArray
        is returned

        >>> ser = pd.Series(pd.Categorical(["a", "b", "a"]))
        >>> ser.array
        ['a', 'b', 'a']
        Categories (2, str): ['a', 'b']
        r   r:   s    r<   arrayzIndexOpsMixin.array  s    H "$'''r>   NFr   npt.DTypeLike | Nonecopyboolna_valuerA   
np.ndarrayc                F   t          | j        t                    r | j        j        |f||d|S |rAt          t          |                                                    }t          d| d          |t          j
        uo2|t          j        u o#t          j        | j        t          j                   }| j        }|rf| j        r_t#          ||          st          j        ||          }n|                                }||t          j        t+          |                     <   t          j        ||          }|r|r|sat          j        | j        dd         |dd                   r7|s!|                                }d|j        _        n|                                }|S )a1  
        A NumPy ndarray representing the values in this Series or Index.

        Parameters
        ----------
        dtype : str or numpy.dtype, optional
            The dtype to pass to :meth:`numpy.asarray`.
        copy : bool, default False
            Whether to ensure that the returned value is not a view on
            another array. Note that ``copy=False`` does not *ensure* that
            ``to_numpy()`` is no-copy. Rather, ``copy=True`` ensure that
            a copy is made, even if not strictly necessary.
        na_value : Any, optional
            The value to use for missing values. The default value depends
            on `dtype` and the type of the array.
        **kwargs
            Additional keywords passed through to the ``to_numpy`` method
            of the underlying array (for extension arrays).

        Returns
        -------
        numpy.ndarray
            The NumPy ndarray holding the values from this Series or Index.
            The dtype of the array may differ. See Notes.

        See Also
        --------
        Series.array : Get the actual data stored within.
        Index.array : Get the actual data stored within.
        DataFrame.to_numpy : Similar method for DataFrame.

        Notes
        -----
        The returned array will be the same up to equality (values equal
        in `self` will be equal in the returned array; likewise for values
        that are not equal). When `self` contains an ExtensionArray, the
        dtype may be different. For example, for a category-dtype Series,
        ``to_numpy()`` will return a NumPy array and the categorical dtype
        will be lost.

        For NumPy dtypes, this will be a reference to the actual data stored
        in this Series or Index (assuming ``copy=False``). Modifying the result
        in place will modify the data stored in the Series or Index (not that
        we recommend doing that).

        For extension types, ``to_numpy()`` *may* require copying data and
        coercing the result to a NumPy type (possibly object), which may be
        expensive. When you need a no-copy reference to the underlying data,
        :attr:`Series.array` should be used instead.

        This table lays out the different dtypes and default return types of
        ``to_numpy()`` for various dtypes within pandas.

        ================== ================================
        dtype              array type
        ================== ================================
        category[T]        ndarray[T] (same dtype as input)
        period             ndarray[object] (Periods)
        interval           ndarray[object] (Intervals)
        IntegerNA          ndarray[object]
        datetime64[ns]     datetime64[ns]
        datetime64[ns, tz] ndarray[object] (Timestamps)
        ================== ================================

        Examples
        --------
        >>> ser = pd.Series(pd.Categorical(["a", "b", "a"]))
        >>> ser.to_numpy()
        array(['a', 'b', 'a'], dtype=object)

        Specify the `dtype` to control how datetime-aware data is represented.
        Use ``dtype=object`` to return an ndarray of pandas :class:`Timestamp`
        objects, each with the correct ``tz``.

        >>> ser = pd.Series(pd.date_range("2000", periods=2, tz="CET"))
        >>> ser.to_numpy(dtype=object)
        array([Timestamp('2000-01-01 00:00:00+0100', tz='CET'),
               Timestamp('2000-01-02 00:00:00+0100', tz='CET')],
              dtype=object)

        Or ``dtype='datetime64[ns]'`` to return an ndarray of native
        datetime64 values. The values are converted to UTC and the timezone
        info is dropped.

        >>> ser.to_numpy(dtype="datetime64[ns]")
        ... # doctest: +ELLIPSIS
        array(['1999-12-31T23:00:00.000000000', '2000-01-01T23:00:00...'],
              dtype='datetime64[ns]')
        )r   r   z/to_numpy() got an unexpected keyword argument 'rf   )r   Nr   F)rr   r   r   r   to_numpyr   r   keys	TypeErrorr   
no_defaultru   nan
issubdtypefloatingr   hasnansr   asarrayr   
asanyarrayr    shares_memoryviewflags	writeable)	r;   r   r   r   r   r   fillnavaluesresults	            r<   r   zIndexOpsMixin.to_numpy7  s   @ dj.11 	&4:&uU4(UUfUUU 	D//00HM(MMM  
 CN* T'RBM$*bk,R,RS 	  		9dl 		9#FH55 ' F%88808F2=d,,-F%000 	+ 	+ 	+RaR 0&!*== + +#[[]]F-2FL**#[[]]Fr>   c                    | j          S )a  
        Indicator whether Index is empty.

        An Index is considered empty if it has no elements. This property can be
        useful for quickly checking the state of an Index, especially in data
        processing and analysis workflows where handling of empty datasets might
        be required.

        Returns
        -------
        bool
            If Index is empty, return True, if not return False.

        See Also
        --------
        Index.size : Return the number of elements in the underlying data.

        Examples
        --------
        >>> idx = pd.Index([1, 2, 3])
        >>> idx
        Index([1, 2, 3], dtype='int64')
        >>> idx.empty
        False

        >>> idx_empty = pd.Index([])
        >>> idx_empty
        Index([], dtype='object')
        >>> idx_empty.empty
        True

        If we only have NaNs in our DataFrame, it is not considered empty!

        >>> idx = pd.Index([np.nan, np.nan])
        >>> idx
        Index([nan, nan], dtype='float64')
        >>> idx.empty
        False
        )r   r:   s    r<   emptyzIndexOpsMixin.empty  s    T 9}r>   Tr~   AxisInt | Noneskipnac                    | j         }t          j        |           t          j        |||          }t	          |t
                    r|                    |          S t          j        ||          }|S )aJ  
        Return int position of the largest value in the Series.

        If the maximum is achieved in multiple locations,
        the first row position is returned.

        Parameters
        ----------
        axis : None
            Unused. Parameter needed for compatibility with DataFrame.
        skipna : bool, default True
            Exclude NA/null values. If the entire Series is NA, or if ``skipna=False``
            and there is an NA value, this method will raise a ``ValueError``.
        *args, **kwargs
            Additional arguments and keywords for compatibility with NumPy.

        Returns
        -------
        int
            Row position of the maximum value.

        See Also
        --------
        Series.argmax : Return position of the maximum value.
        Series.argmin : Return position of the minimum value.
        numpy.ndarray.argmax : Equivalent method for numpy arrays.
        Series.idxmax : Return index label of the maximum values.
        Series.idxmin : Return index label of the minimum values.

        Examples
        --------
        Consider dataset containing cereal calories

        >>> s = pd.Series(
        ...     [100.0, 110.0, 120.0, 110.0],
        ...     index=[
        ...         "Corn Flakes",
        ...         "Almond Delight",
        ...         "Cinnamon Toast Crunch",
        ...         "Cocoa Puff",
        ...     ],
        ... )
        >>> s
        Corn Flakes              100.0
        Almond Delight           110.0
        Cinnamon Toast Crunch    120.0
        Cocoa Puff               110.0
        dtype: float64

        >>> s.argmax()
        np.int64(2)
        >>> s.argmin()
        np.int64(0)

        The maximum cereal calories is the third element and
        the minimum cereal calories is the first element,
        since series is zero-indexed.
        r   )	r   r   validate_minmax_axisvalidate_argmax_with_skipnarr   r'   argmaxr#   	nanargmaxr;   r~   r   r   r   delegater   s          r<   r   zIndexOpsMixin.argmax  s    z <
%%%/fEEh// 	??&?111%hv>>>F Mr>   c                    | j         }t          j        |           t          j        |||          }t	          |t
                    r|                    |          S t          j        ||          }|S )aK  
        Return int position of the smallest value in the Series.

        If the minimum is achieved in multiple locations,
        the first row position is returned.

        Parameters
        ----------
        axis : None
            Unused. Parameter needed for compatibility with DataFrame.
        skipna : bool, default True
            Exclude NA/null values. If the entire Series is NA, or if ``skipna=False``
            and there is an NA value, this method will raise a ``ValueError``.
        *args, **kwargs
            Additional arguments and keywords for compatibility with NumPy.

        Returns
        -------
        int
            Row position of the minimum value.

        See Also
        --------
        Series.argmin : Return position of the minimum value.
        Series.argmax : Return position of the maximum value.
        numpy.ndarray.argmin : Equivalent method for numpy arrays.
        Series.idxmin : Return index label of the minimum values.
        Series.idxmax : Return index label of the maximum values.

        Examples
        --------
        Consider dataset containing cereal calories

        >>> s = pd.Series(
        ...     [100.0, 110.0, 120.0, 110.0],
        ...     index=[
        ...         "Corn Flakes",
        ...         "Almond Delight",
        ...         "Cinnamon Toast Crunch",
        ...         "Cocoa Puff",
        ...     ],
        ... )
        >>> s
        Corn Flakes              100.0
        Almond Delight           110.0
        Cinnamon Toast Crunch    120.0
        Cocoa Puff               110.0
        dtype: float64

        >>> s.argmax()
        np.int64(2)
        >>> s.argmin()
        np.int64(0)

        The maximum cereal calories is the third element and
        the minimum cereal calories is the first element,
        since series is zero-indexed.
        r   )	r   r   r   r   rr   r'   argminr#   	nanargminr   s          r<   r   zIndexOpsMixin.argmin3  r   r>   rs   c                4    | j                                         S )a   
        Return a list of the values.

        These are each a scalar type, which is a Python scalar
        (for str, int, float) or a pandas scalar
        (for Timestamp/Timedelta/Interval/Period)

        Returns
        -------
        list
            List containing the values as Python or pandas scalers.

        See Also
        --------
        numpy.ndarray.tolist : Return the array as an a.ndim-levels deep
            nested list of Python scalars.

        Examples
        --------
        For Series

        >>> s = pd.Series([1, 2, 3])
        >>> s.to_list()
        [1, 2, 3]

        For Index:

        >>> idx = pd.Index([1, 2, 3])
        >>> idx
        Index([1, 2, 3], dtype='int64')

        >>> idx.to_list()
        [1, 2, 3]
        )r   r   r:   s    r<   r   zIndexOpsMixin.tolist|  s    F |""$$$r>   r+   c                    t          | j        t          j                  st	          | j                  S t          | j        j        t          | j        j                            S )aD  
        Return an iterator of the values.

        These are each a scalar type, which is a Python scalar
        (for str, int, float) or a pandas scalar
        (for Timestamp/Timedelta/Interval/Period)

        Returns
        -------
        iterator
            An iterator yielding scalar values from the Series.

        See Also
        --------
        Series.items : Lazily iterate over (index, value) tuples.

        Examples
        --------
        >>> s = pd.Series([1, 2, 3])
        >>> for x in s:
        ...     print(x)
        1
        2
        3
        )	rr   r   ru   rv   r   mapr   ranger   r:   s    r<   __iter__zIndexOpsMixin.__iter__  sM    6 $,
33 	D%%%t|(%0A*B*BCCCr>   c                ^    t          t          |                                                     S )a  
        Return True if there are any NaNs.

        Enables various performance speedups.

        Returns
        -------
        bool

        See Also
        --------
        Series.isna : Detect missing values.
        Series.notna : Detect existing (non-missing) values.

        Examples
        --------
        >>> s = pd.Series([1, 2, 3, None])
        >>> s
        0    1.0
        1    2.0
        2    3.0
        3    NaN
        dtype: float64
        >>> s.hasnans
        True
        )r   r    anyr:   s    r<   r   zIndexOpsMixin.hasnans  s"    < DJJNN$$%%%r>   c                    | j         }t          |t                    r|                    ||          S t	          j        |||          S )a  
        An internal function that maps values using the input
        correspondence (which can be a dict, Series, or function).

        Parameters
        ----------
        mapper : function, dict, or Series
            The input correspondence object
        na_action : {None, 'ignore'}
            If 'ignore', propagate NA values, without passing them to the
            mapping function

        Returns
        -------
        Union[Index, MultiIndex], inferred
            The output of the mapping function applied to the index.
            If the function returns a tuple with more than one element
            a MultiIndex will be returned.
        )	na_action)r   rr   r'   r   r"   	map_array)r;   mapperr   arrs       r<   _map_valueszIndexOpsMixin._map_values  sK    * lc>** 	8776Y7777#C9EEEEr>   	normalizesort	ascendingdropnar2   c                6    t          j        | |||||          S )aA  
        Return a Series containing counts of unique values.

        The resulting object will be in descending order so that the
        first element is the most frequently-occurring element.
        Excludes NA values by default.

        Parameters
        ----------
        normalize : bool, default False
            If True then the object returned will contain the relative
            frequencies of the unique values.
        sort : bool, default True
            Stable sort by frequencies when True. Preserve the order of the data
            when False.

            .. versionchanged:: 3.0.0

                Prior to 3.0.0, the sort was unstable.
        ascending : bool, default False
            Sort in ascending order.
        bins : int, optional
            Rather than count values, group them into half-open bins,
            a convenience for ``pd.cut``, only works with numeric data.
        dropna : bool, default True
            Don't include counts of NaN.

        Returns
        -------
        Series
            Series containing counts of unique values.

        See Also
        --------
        Series.count: Number of non-NA elements in a Series.
        DataFrame.count: Number of non-NA elements in a DataFrame.
        DataFrame.value_counts: Equivalent method on DataFrames.

        Examples
        --------
        >>> index = pd.Index([3, 1, 2, 3, 4, np.nan])
        >>> index.value_counts()
        3.0    2
        1.0    1
        2.0    1
        4.0    1
        Name: count, dtype: int64

        With `normalize` set to `True`, returns the relative frequency by
        dividing all values by the sum of values.

        >>> s = pd.Series([3, 1, 2, 3, 4, np.nan])
        >>> s.value_counts(normalize=True)
        3.0    0.4
        1.0    0.2
        2.0    0.2
        4.0    0.2
        Name: proportion, dtype: float64

        **bins**

        Bins can be useful for going from a continuous variable to a
        categorical variable; instead of counting unique
        apparitions of values, divide the index in the specified
        number of half-open bins.

        >>> s.value_counts(bins=3)
        (0.996, 2.0]    2
        (2.0, 3.0]      2
        (3.0, 4.0]      1
        Name: count, dtype: int64

        **dropna**

        With `dropna` set to `False` we can also see NaN index values.

        >>> s.value_counts(dropna=False)
        3.0    2
        1.0    1
        2.0    1
        4.0    1
        NaN    1
        Name: count, dtype: int64

        **Categorical Dtypes**

        Rows with categorical type will be counted as one group
        if they have same categories and order.
        In the example below, even though ``a``, ``c``, and ``d``
        all have the same data types of ``category``,
        only ``c`` and ``d`` will be counted as one group
        since ``a`` doesn't have the same categories.

        >>> df = pd.DataFrame({"a": [1], "b": ["2"], "c": [3], "d": [3]})
        >>> df = df.astype({"a": "category", "c": "category", "d": "category"})
        >>> df
           a  b  c  d
        0  1  2  3  3

        >>> df.dtypes
        a    category
        b      str
        c    category
        d    category
        dtype: object

        >>> df.dtypes.value_counts()
        category    2
        category    1
        str         1
        Name: count, dtype: int64
        )r   r   r   binsr   )r"   value_counts_internal)r;   r   r   r   r   r   s         r<   value_countszIndexOpsMixin.value_counts   s1    p /
 
 
 	
r>   c                    | j         }t          |t          j                  s|                                }nt          j        |          }|S rV   )r   rr   ru   rv   uniquer"   unique1d)r;   r   r   s      r<   r   zIndexOpsMixin.unique  sA    &"*-- 	1]]__FF(00Fr>   c                j    |                                  }|rt          |          }t          |          S )a  
        Return number of unique elements in the object.

        Excludes NA values by default.

        Parameters
        ----------
        dropna : bool, default True
            Don't include NaN in the count.

        Returns
        -------
        int
            An integer indicating the number of unique elements in the object.

        See Also
        --------
        DataFrame.nunique: Method nunique for DataFrame.
        Series.count: Count non-NA/null observations in the Series.

        Examples
        --------
        >>> s = pd.Series([1, 3, 5, 7, 7])
        >>> s
        0    1
        1    3
        2    5
        3    7
        4    7
        dtype: int64

        >>> s.nunique()
        4
        )r   r!   r   )r;   r   uniqss      r<   nuniquezIndexOpsMixin.nunique  s3    H  	/'..E5zzr>   c                P    |                      d          t          |           k    S )a  
        Return True if values in the object are unique.

        Returns
        -------
        bool

        See Also
        --------
        Series.unique : Return unique values of Series object.
        Series.drop_duplicates : Return Series with duplicate values removed.
        Series.duplicated : Indicate duplicate Series values.

        Examples
        --------
        >>> s = pd.Series([1, 2, 3])
        >>> s.is_unique
        True

        >>> s = pd.Series([1, 2, 3, 1])
        >>> s.is_unique
        False
        F)r   )r   r   r:   s    r<   	is_uniquezIndexOpsMixin.is_unique  s#    2 ||5|))SYY66r>   c                .    ddl m}  ||           j        S )a  
        Return True if values in the object are monotonically increasing.

        Returns
        -------
        bool

        See Also
        --------
        Series.is_monotonic_decreasing : Return boolean if values in the object are
            monotonically decreasing.

        Examples
        --------
        >>> s = pd.Series([1, 2, 2])
        >>> s.is_monotonic_increasing
        True

        >>> s = pd.Series([3, 2, 1])
        >>> s.is_monotonic_increasing
        False
        r   r1   )pandasr1   is_monotonic_increasingr;   r1   s     r<   r  z%IndexOpsMixin.is_monotonic_increasing  '    0 	!     uT{{22r>   c                .    ddl m}  ||           j        S )a  
        Return True if values in the object are monotonically decreasing.

        Returns
        -------
        bool

        See Also
        --------
        Series.is_monotonic_increasing : Return boolean if values in the object are
            monotonically increasing.

        Examples
        --------
        >>> s = pd.Series([3, 2, 2, 1])
        >>> s.is_monotonic_decreasing
        True

        >>> s = pd.Series([1, 2, 3])
        >>> s.is_monotonic_decreasing
        False
        r   r  )r  r1   is_monotonic_decreasingr  s     r<   r	  z%IndexOpsMixin.is_monotonic_decreasing  r  r>   rO   c                $   t          | j        d          r| j                            |          S | j        j        }|rQt	          | j                  r=t          s6t          t          j	        | j
                  }|t          j        |          z  }|S )a  
        Memory usage of the values.

        Parameters
        ----------
        deep : bool, default False
            Introspect the data deeply, interrogate
            `object` dtypes for system-level memory consumption.

        Returns
        -------
        bytes used
            Returns memory usage of the values in the Index in bytes.

        See Also
        --------
        numpy.ndarray.nbytes : Total bytes consumed by the elements of the
            array.

        Notes
        -----
        Memory usage does not include memory consumed by elements that
        are not components of the array if deep=False or if used on PyPy

        Examples
        --------
        >>> idx = pd.Index([1, 2, 3])
        >>> idx.memory_usage()
        24
        rM   rN   )rG   r   rM   r   r   r   r   r	   ru   rv   r   r   memory_usage_of_objects)r;   rO   vr   s       r<   _memory_usagezIndexOpsMixin._memory_usage  s    @ 4:~.. 	:** +    J 	5ODJ// 	5 	5"*dl33F,V444Ar>   use_na_sentinel"tuple[npt.NDArray[np.intp], Index]c                   t          j        | j        ||          \  }}|j        t          j        k    r|                    t          j                  }t          | t                    r4t          |           dk    r| dd         }nN|                     |          }n8ddlm} 	  ||| j        d          }n# t          $ r  ||d          }Y nw xY w||fS )a  
        Encode the object as an enumerated type or categorical variable.

        This method is useful for obtaining a numeric representation of an
        array when all that matters is identifying distinct values. `factorize`
        is available as both a top-level function :func:`pandas.factorize`,
        and as a method :meth:`Series.factorize` and :meth:`Index.factorize`.

        Parameters
        ----------
        sort : bool, default False
            Sort `uniques` and shuffle `codes` to maintain the
            relationship.
        use_na_sentinel : bool, default True
            If True, the sentinel -1 will be used for NaN values. If False,
            NaN values will be encoded as non-negative integers and will not drop the
            NaN from the uniques of the values.

        Returns
        -------
        codes : ndarray
            An integer ndarray that's an indexer into `uniques`.
            ``uniques.take(codes)`` will have the same values as `values`.
        uniques : ndarray, Index, or Categorical
            The unique valid values. When `values` is Categorical, `uniques`
            is a Categorical. When `values` is some other pandas object, an
            `Index` is returned. Otherwise, a 1-D ndarray is returned.

            .. note::

                Even if there's a missing value in `values`, `uniques` will
                *not* contain an entry for it.

        See Also
        --------
        cut : Discretize continuous-valued array.
        unique : Find the unique value in an array.

        Notes
        -----
        Reference :ref:`the user guide <reshaping.factorize>` for more examples.

        Examples
        --------
        These examples all show factorize as a top-level method like
        ``pd.factorize(values)``. The results are identical for methods like
        :meth:`Series.factorize`.

        >>> codes, uniques = pd.factorize(
        ...     np.array(["b", "b", "a", "c", "b"], dtype="O")
        ... )
        >>> codes
        array([0, 0, 1, 2, 0])
        >>> uniques
        array(['b', 'a', 'c'], dtype=object)

        With ``sort=True``, the `uniques` will be sorted, and `codes` will be
        shuffled so that the relationship is the maintained.

        >>> codes, uniques = pd.factorize(
        ...     np.array(["b", "b", "a", "c", "b"], dtype="O"), sort=True
        ... )
        >>> codes
        array([1, 1, 0, 2, 1])
        >>> uniques
        array(['a', 'b', 'c'], dtype=object)

        When ``use_na_sentinel=True`` (the default), missing values are indicated in
        the `codes` with the sentinel value ``-1`` and missing values are not
        included in `uniques`.

        >>> codes, uniques = pd.factorize(
        ...     np.array(["b", None, "a", "c", "b"], dtype="O")
        ... )
        >>> codes
        array([ 0, -1,  1,  2,  0])
        >>> uniques
        array(['b', 'a', 'c'], dtype=object)

        Thus far, we've only factorized lists (which are internally coerced to
        NumPy arrays). When factorizing pandas objects, the type of `uniques`
        will differ. For Categoricals, a `Categorical` is returned.

        >>> cat = pd.Categorical(["a", "a", "c"], categories=["a", "b", "c"])
        >>> codes, uniques = pd.factorize(cat)
        >>> codes
        array([0, 0, 1])
        >>> uniques
        ['a', 'c']
        Categories (3, str): ['a', 'b', 'c']

        Notice that ``'b'`` is in ``uniques.categories``, despite not being
        present in ``cat.values``.

        For all other pandas objects, an Index of the appropriate type is
        returned.

        >>> cat = pd.Series(["a", "a", "c"])
        >>> codes, uniques = pd.factorize(cat)
        >>> codes
        array([0, 0, 1])
        >>> uniques
        Index(['a', 'c'], dtype='str')

        If NaN is in the values, and we want to include NaN in the uniques of the
        values, it can be achieved by setting ``use_na_sentinel=False``.

        >>> values = np.array([1, 2, 1, np.nan])
        >>> codes, uniques = pd.factorize(values)  # default: use_na_sentinel=True
        >>> codes
        array([ 0,  1,  0, -1])
        >>> uniques
        array([1., 2.])

        >>> codes, uniques = pd.factorize(values, use_na_sentinel=False)
        >>> codes
        array([0, 1, 0, 2])
        >>> uniques
        array([ 1.,  2., nan])
        )r   r  r   Nr  F)r   r   )r   )r"   	factorizer   r   ru   float16astypefloat32rr   r   r   r=   r  r1   NotImplementedError)r;   r   r  codesuniquesr1   s         r<   r  zIndexOpsMixin.factorize1  s   z $-Lt_
 
 
w =BJ&&nnRZ00GdM** 	54yyA~~rr(++G44$$$$$$5%tzFFF& 5 5 5  %e4445 g~s   $B8 8CC.ri   r/   sideLiteral['left', 'right']sorterr-   np.intpc                    d S rV   rj   r;   ri   r  r  s       r<   searchsortedzIndexOpsMixin.searchsorted  s	     #r>   npt.ArrayLike | ExtensionArraynpt.NDArray[np.intp]c                    d S rV   rj   r  s       r<   r  zIndexOpsMixin.searchsorted  s	      #sr>   left$NumpyValueArrayLike | ExtensionArrayNumpySorter | Nonenpt.NDArray[np.intp] | np.intpc                   t          |t                    r'dt          |          j         d}t	          |          | j        }t          |t          j                  s|                    |||          S t          j        ||||          S )a  
        Find indices where elements should be inserted to maintain order.

        Find the indices into a sorted Index `self` such that, if the
        corresponding elements in `value` were inserted before the indices,
        the order of `self` would be preserved.

        .. note::

            The Index *must* be monotonically sorted, otherwise
            wrong locations will likely be returned. Pandas does *not*
            check this for you.

        Parameters
        ----------
        value : array-like or scalar
            Values to insert into `self`.
        side : {{'left', 'right'}}, optional
            If 'left', the index of the first suitable location found is given.
            If 'right', return the last such index.  If there is no suitable
            index, return either 0 or N (where N is the length of `self`).
        sorter : 1-D array-like, optional
            Optional array of integer indices that sort `self` into ascending
            order. They are typically the result of ``np.argsort``.

        Returns
        -------
        int or array of int
            A scalar or array of insertion points with the
            same shape as `value`.

        See Also
        --------
        sort_values : Sort by the values along either axis.
        numpy.searchsorted : Similar method from NumPy.

        Notes
        -----
        Binary search is used to find the required insertion points.

        Examples
        --------
        >>> ser = pd.Series([1, 2, 3])
        >>> ser
        0    1
        1    2
        2    3
        dtype: int64

        >>> ser.searchsorted(4)
        np.int64(3)

        >>> ser.searchsorted([0, 4])
        array([0, 3])

        >>> ser.searchsorted([1, 3], side="left")
        array([0, 2])

        >>> ser.searchsorted([1, 3], side="right")
        array([1, 3])

        >>> ser = pd.Series(pd.to_datetime(["3/11/2000", "3/12/2000", "3/13/2000"]))
        >>> ser
        0   2000-03-11
        1   2000-03-12
        2   2000-03-13
        dtype: datetime64[us]

        >>> ser.searchsorted("3/14/2000")
        np.int64(3)

        >>> ser = pd.Categorical(
        ...     ["apple", "bread", "bread", "cheese", "milk"], ordered=True
        ... )
        >>> ser
        ['apple', 'bread', 'bread', 'cheese', 'milk']
        Categories (4, str): ['apple' < 'bread' < 'cheese' < 'milk']

        >>> ser.searchsorted("bread")
        np.int64(1)

        >>> ser.searchsorted(["bread"], side="right")
        array([3])

        If the values are not monotonically sorted, wrong locations
        may be returned:

        >>> ser = pd.Series([2, 1, 3])
        >>> ser
        0    2
        1    1
        2    3
        dtype: int64

        >>> ser.searchsorted(1)  # doctest: +SKIP
        0  # wrong result, correct would be 1
        z(Value must be 1-D array-like or scalar, z is not supported)r  r  )
rr   r   r9   rX   r   r   ru   rv   r  r"   )r;   ri   r  r  msgr   s         r<   r  zIndexOpsMixin.searchsorted  s    N e\** 	";;;'; ; ;  S//!&"*-- 	H&&u4&GGG&	
 
 
 	
r>   firstkeepr*  r,   c               @    |                      |          }| |          S Nr)  )_duplicated)r;   r*  
duplicateds      r<   drop_duplicateszIndexOpsMixin.drop_duplicatesU  s%    %%4%00
ZK  r>   npt.NDArray[np.bool_]c                    | j         }t          |t                    r|                    |          S t	          j        ||          S r,  )r   rr   r'   r.  r"   )r;   r*  r   s      r<   r-  zIndexOpsMixin._duplicatedZ  sE    lc>** 	->>t>,,,$St4444r>   c                   t          j        | |          }| j        }t          |dd          }t          j        ||j                  }t          |          }t          |t                    r%t          j
        |j        |j        |j                  }t          j        d          5  t          j        |||          }d d d            n# 1 swxY w Y   |                     |||          S )NT)extract_numpyextract_rangeignore)all)r   other)r$   get_op_result_namer   r)   maybe_prepare_scalar_for_opr   r(   rr   r   ru   arangestartstopsteperrstatearithmetic_op_construct_result)r;   r7  opres_namelvaluesrvaluesr   s          r<   _arith_methodzIndexOpsMixin._arith_methoda  s   )$66,TNNN1'7=II099gu%% 	Kiw|W\JJG[X&&& 	= 	=&w<<F	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= %%f85%IIIs   'C

CCc                     t          |           )z~
        Construct an appropriately-wrapped result from the ArrayLike result
        of an arithmetic-like operation.
        r   )r;   r   r   r7  s       r<   r@  zIndexOpsMixin._construct_resultp  s    
 "$'''r>   )r6   r   )r6   r   )r6   r   )r6   r   rW   )r6   r'   )r   r   r   r   r   rA   r6   r   )r6   r   )NT)r~   r   r   r   r6   rK   )r6   rs   )r6   r+   rV   )FTFNT)
r   r   r   r   r   r   r   r   r6   r2   )T)r   r   r6   rK   )F)rO   r   r6   rK   )FT)r   r   r  r   r6   r  )..)ri   r/   r  r  r  r-   r6   r  )ri   r  r  r  r  r-   r6   r   )r"  N)ri   r#  r  r  r  r$  r6   r%  )r*  r,   r6   r   )r(  )r*  r,   r6   r0  )/rX   rY   rZ   r[   __array_priority__	frozensetr   r\   r]   r   r   r
   r   Tr   r   r{   r   r   r   r   r   r   r   r   r   r   r   to_listr   r   r   r   r   r   r   r  r  r	  r  r  r   r  r/  r-  rE  r@  rj   r>   r<   r   r     s         
 $-I	
% %M     ( ( ( X( ( ( ( X( 	 	 	 U	 		 	 	AB " " " X"$( ( ( (    X@ !S !S U!SF # # # X#@  !  !  ! X !D C( C( C( XC(N '+>	E E E E EN ( ( ( X U(V ;?G G G G GT ;?G G G G GR#% #% #% #%J GD D D DB & & & ^&> F F F UF:  
 
 
 
 
B   & & & & U&P 7 7 7 X74 3 3 3 X36 3 3 3 X36 ( ( ( ( U(X  $S S S S St  *-!	    X  *-!	# # # # X# *0%)	x
 x
 x
 x
 x
t 3: ! ! ! ! ! !
 5 5 5 5 U5J J J( ( ( ( (r>   r   )Kr[   
__future__r   typingr   r   r   r   r   r	   r
   r   numpyru   pandas._libsr   pandas._typingr   r   r   r   r   r   pandas.compatr   pandas.compat.numpyr   r   pandas.errorsr   pandas.util._decoratorsr   pandas.core.dtypes.castr   pandas.core.dtypes.commonr   r   pandas.core.dtypes.dtypesr   pandas.core.dtypes.genericr   r   r   r   pandas.core.dtypes.missingr    r!   pandas.corer"   r#   r$   pandas.core.accessorr%   pandas.core.arrayliker&   pandas.core.arraysr'   pandas.core.constructionr(   r)   collections.abcr*   r+   r,   r-   r.   r/   r  r0   r1   r2   r4   r`   rl   r   rj   r>   r<   <module>r_     s    # " " " " "	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	                                . . . . . . - - - - - - 2 2 2 2 2 2 4 4 4 4 4 4        5 4 4 4 4 4                  
         
 / . . . . . * * * * * * - - - - - -       
         
                    ,$ ,$ ,$ ,$ ,$= ,$ ,$ ,$^- - - - - - - -Dd d d d dWX& d d dNi( i( i( i( i(H i( i( i( i( i(r>   