B
    W0d!2                 @  s:  d Z 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 ddlmZmZ ddlmZmZ ddlmZ dd	lmZ dd
lm  mZ ddlmZ erddlm Z  dddddZ!ddddZ"dddddZ#dddddZ$ddd d!d"Z%d#d#d$d%d&Z&d'd(d)d*d+d,d-d.Z'dd/dd0d1Z(d
S )2z
aggregation.py contains utility functions to handle multiple named and lambda
kwarg aggregations in groupby and DataFrame/Series aggregation
    )annotations)defaultdict)partial)TYPE_CHECKINGAnyCallableDefaultDictHashableIterableSequence)AggFuncTypeFrameOrSeries)is_dict_likeis_list_like)	ABCSeries)SpecificationErrorN)Index)SerieszAggFuncType | NonezCtuple[bool, AggFuncType | None, list[str] | None, list[int] | None])funcreturnc             K  st   | dkot f |}d}d}|sVt| trFt| tt| krFtdn| dkrVtd|rht|\} }}|| ||fS )a  
    This is the internal function to reconstruct func given if there is relabeling
    or not and also normalize the keyword to get new order of columns.

    If named aggregation is applied, `func` will be None, and kwargs contains the
    column and aggregation function information to be parsed;
    If named aggregation is not applied, `func` is either string (e.g. 'min') or
    Callable, or list of them (e.g. ['min', np.max]), or the dictionary of column name
    and str/Callable/list of them (e.g. {'A': 'min'}, or {'A': [np.min, lambda x: x]})

    If relabeling is True, will return relabeling, reconstructed func, column
    names, and the reconstructed order of columns.
    If relabeling is False, the columns and order will be None.

    Parameters
    ----------
    func: agg function (e.g. 'min' or Callable) or list of agg functions
        (e.g. ['min', np.max]) or dictionary (e.g. {'A': ['min', np.max]}).
    **kwargs: dict, kwargs used in is_multi_agg_with_relabel and
        normalize_keyword_aggregation function for relabelling

    Returns
    -------
    relabelling: bool, if there is relabelling or not
    func: normalized and mangled func
    columns: list of column names
    order: list of columns indices

    Examples
    --------
    >>> reconstruct_func(None, **{"foo": ("col", "min")})
    (True, defaultdict(<class 'list'>, {'col': ['min']}), ('foo',), array([0]))

    >>> reconstruct_func("min")
    (False, 'min', None, None)
    NzFFunction names must be unique if there is no new column names assignedz4Must provide 'func' or tuples of '(column, aggfunc).)is_multi_agg_with_relabel
isinstancelistlensetr   	TypeErrornormalize_keyword_aggregation)r   kwargsZ
relabelingcolumnsorder r    I/var/www/html/venv/lib/python3.7/site-packages/pandas/core/aggregation.pyreconstruct_func'   s    'r"   bool)r   c              K  s"   t dd |  D o t| dkS )ax  
    Check whether kwargs passed to .agg look like multi-agg with relabeling.

    Parameters
    ----------
    **kwargs : dict

    Returns
    -------
    bool

    Examples
    --------
    >>> is_multi_agg_with_relabel(a="max")
    False
    >>> is_multi_agg_with_relabel(a_max=("a", "max"), a_min=("a", "min"))
    True
    >>> is_multi_agg_with_relabel()
    False
    c             s  s$   | ]}t |tot|d kV  qdS )   N)r   tupler   ).0vr    r    r!   	<genexpr>z   s    z,is_multi_agg_with_relabel.<locals>.<genexpr>r   )allvaluesr   )r   r    r    r!   r   e   s    r   dictz!tuple[dict, list[str], list[int]])r   r   c             C  s   t t}g }tt|   \}}x6|D ].\}}|| | ||t|pN|f q&W t|}dd | D }t|}	t|		|}
|||
fS )aL  
    Normalize user-provided "named aggregation" kwargs.
    Transforms from the new ``Mapping[str, NamedAgg]`` style kwargs
    to the old Dict[str, List[scalar]]].

    Parameters
    ----------
    kwargs : dict

    Returns
    -------
    aggspec : dict
        The transformed kwargs.
    columns : List[str]
        The user-provided keys.
    col_idx_order : List[int]
        List of columns indices.

    Examples
    --------
    >>> normalize_keyword_aggregation({"output": ("input", "sum")})
    (defaultdict(<class 'list'>, {'input': ['sum']}), ('output',), array([0]))
    c             S  s,   g | ]$\}}|D ]}|t |p"|fqqS r    )comget_callable_name)r&   columnaggfuncsaggfuncr    r    r!   
<listcomp>   s   z1normalize_keyword_aggregation.<locals>.<listcomp>)
r   r   zipitemsappendr,   r-   _make_unique_kwarg_listr   get_indexer)r   Zaggspecr   r   pairsr.   r0   Zuniquified_orderZaggspec_orderZuniquified_aggspeccol_idx_orderr    r    r!   r      s    r   zSequence[tuple[Any, Any]])seqr   c               s    fddt  D S )a  
    Uniquify aggfunc name of the pairs in the order list

    Examples:
    --------
    >>> kwarg_list = [('a', '<lambda>'), ('a', '<lambda>'), ('b', '<lambda>')]
    >>> _make_unique_kwarg_list(kwarg_list)
    [('a', '<lambda>_0'), ('a', '<lambda>_1'), ('b', '<lambda>')]
    c          
     sN   g | ]F\}}  |d krF|d d|d  t d|  |gfn|qS )   r   _N)countjoinstr)r&   ipair)r9   r    r!   r1      s   z+_make_unique_kwarg_list.<locals>.<listcomp>)	enumerate)r9   r    )r9   r!   r5      s    
r5   zSequence[Any])r/   r   c             C  s`   t | dkr| S d}g }xB| D ]:}t|dkrNt|}d| d|_|d7 }|| qW |S )aJ  
    Possibly mangle a list of aggfuncs.

    Parameters
    ----------
    aggfuncs : Sequence

    Returns
    -------
    mangled: list-like
        A new AggSpec sequence, where lambdas have been converted
        to have unique names.

    Notes
    -----
    If just one aggfunc is passed, the name will not be mangled.
    r:   r   z<lambda>z<lambda_>)r   r,   r-   r   __name__r4   )r/   r?   mangled_aggfuncsr0   r    r    r!   _managle_lambda_list   s    
rE   r   )agg_specr   c             C  sp   t | }|st| s| S t|  }|rdxD|  D ].\}}t|rRt |sRt|}n|}|||< q0W nt| }|S )aZ  
    Make new lambdas with unique names.

    Parameters
    ----------
    agg_spec : Any
        An argument to GroupBy.agg.
        Non-dict-like `agg_spec` are pass through as is.
        For dict-like `agg_spec` a new spec is returned
        with name-mangled lambdas.

    Returns
    -------
    mangled : Any
        Same type as the input.

    Examples
    --------
    >>> maybe_mangle_lambdas('sum')
    'sum'
    >>> maybe_mangle_lambdas([lambda: 1, lambda: 2])  # doctest: +SKIP
    [<function __main__.<lambda_0>,
     <function pandas...._make_lambda.<locals>.f(*args, **kwargs)>]
    )r   r   typer3   rE   )rF   Zis_dictZmangled_aggspeckeyr/   rD   r    r    r!   maybe_mangle_lambdas   s    

rI   r   zdict[str, list[Callable | str]]zIterable[Hashable]zIterable[int]zdict[Hashable, Series])resultr   r   r   r   c             C  s   dd t t||dd dD }i }d}t| t o@t| jdk}x~| D ]r\}}	| |  }
|rdd |	D }	t|
j	
|	}|
| }
|||t|	  |
_	|
j|d	d
||< |t|	 }qLW |S )a  
    Internal function to reorder result if relabelling is True for
    dataframe.agg, and return the reordered result in dict.

    Parameters:
    ----------
    result: Result from aggregation
    func: Dict of (column name, funcs)
    columns: New columns name for relabelling
    order: New order for relabelling

    Examples:
    ---------
    >>> result = DataFrame({"A": [np.nan, 2, np.nan],
    ...       "C": [6, np.nan, np.nan], "B": [np.nan, 4, 2.5]})  # doctest: +SKIP
    >>> funcs = {"A": ["max"], "C": ["max"], "B": ["mean", "min"]}
    >>> columns = ("foo", "aab", "bar", "dat")
    >>> order = [0, 1, 2, 3]
    >>> _relabel_result(result, func, columns, order)  # doctest: +SKIP
    dict(A=Series([2.0, NaN, NaN, NaN], index=["foo", "aab", "bar", "dat"]),
         C=Series([NaN, 6.0, NaN, NaN], index=["foo", "aab", "bar", "dat"]),
         B=Series([NaN, NaN, 2.5, 4.0], index=["foo", "aab", "bar", "dat"]))
    c             S  s   g | ]}|d  qS )r   r    )r&   r@   r    r    r!   r1   >  s    z"relabel_result.<locals>.<listcomp>c             S  s   | d S )Nr:   r    )tr    r    r!   <lambda>>      z relabel_result.<locals>.<lambda>)rH   r   r:   c             S  s$   g | ]}t |tst|n|qS r    )r   r>   r,   r-   )r&   fr    r    r!   r1   ]  s    F)copy)sortedr2   r   r   r   r   r3   Zdropnar   indexr6   Zreindex)rJ   r   r   r   Zreordered_indexesZreordered_result_in_dictidxZreorder_maskcolZfunsr8   r    r    r!   relabel_result   s     rU   z0tuple[list[str], list[str | Callable[..., Any]]]c             C  sj   d}t | }g }x@|  D ]4}t|tsDt|sDt|t|j|	| qW |sbd}t|||fS )a  
    Validates types of user-provided "named aggregation" kwargs.
    `TypeError` is raised if aggfunc is not `str` or callable.

    Parameters
    ----------
    kwargs : dict

    Returns
    -------
    columns : List[str]
        List of user-provied keys.
    func : List[Union[str, callable[...,Any]]]
        List of user-provided aggfuncs

    Examples
    --------
    >>> validate_func_kwargs({'one': 'min', 'two': 'max'})
    (['one', 'two'], ['min', 'max'])
    z-func is expected but received {} in **kwargs.z2Must provide 'func' or named aggregation **kwargs.)
r   r*   r   r>   callabler   formatrG   rC   r4   )r   Ztuple_given_messager   r   Zcol_funcZno_arg_messager    r    r!   validate_func_kwargsj  s    rX   ))__doc__
__future__r   collectionsr   	functoolsr   typingr   r   r   r   r	   r
   r   Zpandas._typingr   r   Zpandas.core.dtypes.commonr   r   Zpandas.core.dtypes.genericr   Zpandas.core.baser   Zpandas.core.commoncorecommonr,   Zpandas.core.indexes.apir   Zpandas.core.seriesr   r"   r   r   r5   rE   rI   rU   rX   r    r    r    r!   <module>   s(   $
>9!,J