U
    CvfJ                     @  s  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
Zd dlmZ d dl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mZ ed
 ZdZdZdZerd dl m!Z! d dl"m#Z# G dd dee Z$G dd de$d Z%G dd de$d Z&dd Z'e'e%d e'e&d dS )    )annotations)TYPE_CHECKINGGenericHashableIterableLiteralSequencecastN)	ArrayLike)duck_array_opsutils)align	broadcast)apply_ufuncdot)is_duck_dask_array)DimsT_Xarray)linearinterpolated_inverted_cdfhazenweibullmedian_unbiasednormal_unbiaseda  
    Reduce this {cls}'s data by a weighted ``{fcn}`` along some dimension(s).

    Parameters
    ----------
    dim : Hashable or Iterable of Hashable, optional
        Dimension(s) over which to apply the weighted ``{fcn}``.
    skipna : bool or None, optional
        If True, skip missing values (as marked by NaN). By default, only
        skips missing values for float dtypes; other dtypes either do not
        have a sentinel missing value (int) or skipna=True has not been
        implemented (object, datetime64 or timedelta64).
    keep_attrs : bool or None, optional
        If True, the attributes (``attrs``) will be copied from the original
        object to the new one.  If False (default), the new object will be
        returned without attributes.

    Returns
    -------
    reduced : {cls}
        New {cls} object with weighted ``{fcn}`` applied to its data and
        the indicated dimension(s) removed.

    Notes
    -----
        Returns {on_zero} if the ``weights`` sum to 0.0 along the reduced
        dimension(s).
    a)  
    Calculate the sum of weights, accounting for missing values in the data.

    Parameters
    ----------
    dim : str or sequence of str, optional
        Dimension(s) over which to sum the weights.
    keep_attrs : bool, optional
        If True, the attributes (``attrs``) will be copied from the original
        object to the new one.  If False (default), the new object will be
        returned without attributes.

    Returns
    -------
    reduced : {cls}
        New {cls} object with the sum of the weights over the given dimension.
    uT	  
    Apply a weighted ``quantile`` to this {cls}'s data along some dimension(s).

    Weights are interpreted as *sampling weights* (or probability weights) and
    describe how a sample is scaled to the whole population [1]_. There are
    other possible interpretations for weights, *precision weights* describing the
    precision of observations, or *frequency weights* counting the number of identical
    observations, however, they are not implemented here.

    For compatibility with NumPy's non-weighted ``quantile`` (which is used by
    ``DataArray.quantile`` and ``Dataset.quantile``), the only interpolation
    method supported by this weighted version corresponds to the default "linear"
    option of ``numpy.quantile``. This is "Type 7" option, described in Hyndman
    and Fan (1996) [2]_. The implementation is largely inspired by a blog post
    from A. Akinshin's [3]_.

    Parameters
    ----------
    q : float or sequence of float
        Quantile to compute, which must be between 0 and 1 inclusive.
    dim : str or sequence of str, optional
        Dimension(s) over which to apply the weighted ``quantile``.
    skipna : bool, optional
        If True, skip missing values (as marked by NaN). By default, only
        skips missing values for float dtypes; other dtypes either do not
        have a sentinel missing value (int) or skipna=True has not been
        implemented (object, datetime64 or timedelta64).
    keep_attrs : bool, optional
        If True, the attributes (``attrs``) will be copied from the original
        object to the new one.  If False (default), the new object will be
        returned without attributes.

    Returns
    -------
    quantiles : {cls}
        New {cls} object with weighted ``quantile`` applied to its data and
        the indicated dimension(s) removed.

    See Also
    --------
    numpy.nanquantile, pandas.Series.quantile, Dataset.quantile, DataArray.quantile

    Notes
    -----
    Returns NaN if the ``weights`` sum to 0.0 along the reduced
    dimension(s).

    References
    ----------
    .. [1] https://notstatschat.rbind.io/2020/08/04/weights-in-statistics/
    .. [2] Hyndman, R. J. & Fan, Y. (1996). Sample Quantiles in Statistical Packages.
           The American Statistician, 50(4), 361–365. https://doi.org/10.2307/2684934
    .. [3] https://aakinshin.net/posts/weighted-quantiles
    	DataArray)Datasetc                   @  s  e Zd ZdZdZddddddZd	d
ddZed>ddd	dddddZd?dd	ddddZ	d@dd	dddddZ
dAdd	dddddZdBdd	dddddZdCdd	dddddZdDdd	dddddZdEdd d	ddd!d"d#Zd$d% ZdFd	ddd&d'd(ZdGd	dddd)d*d+ZdHd	dddd)d,d-ZdId	dddd)d.d/ZdJd	dddd)d0d1ZdKd	dddd)d2d3Zddd4d5d d	dd6dd7d8d9Zd:d;d<d=ZdS )LWeightedzAn object that implements weighted operations.

    You should create a Weighted object by using the ``DataArray.weighted`` or
    ``Dataset.weighted`` methods.

    See Also
    --------
    Dataset.weighted
    DataArray.weighted
    )objweightsr   r   None)r   r   returnc                 C  sh   ddl m} t||stddd }t|jrN|j|jj||jddd}n
||j || _	|| _
d	S )
aH  
        Create a Weighted object

        Parameters
        ----------
        obj : DataArray or Dataset
            Object over which the weighted reduction operation is applied.
        weights : DataArray
            An array of weights associated with the values in the obj.
            Each value in the obj contributes to the reduction operation
            according to its associated weight.

        Notes
        -----
        ``weights`` must be a ``DataArray`` and cannot contain missing values.
        Missing values can be replaced by ``weights.fillna(0)``.
        r   r   z`weights` must be a DataArrayc                 S  s   t |  rtd| S )Nz_`weights` cannot contain missing values. Missing values can be replaced by `weights.fillna(0)`.)r   Zisnullany
ValueError)w r%   8/tmp/pip-unpacked-wheel-h316xyqg/xarray/core/weighted.py_weight_check   s
    z(Weighted.__init__.<locals>._weight_checkdtypeF)datadeepN)xarray.core.dataarrayr   
isinstancer#   r   r*   copyZ
map_blocksr)   r   r   )selfr   r   r   r'   r%   r%   r&   __init__   s    
	

zWeighted.__init__r   dimc                 C  sj   t |tst |ts$|r|gng }nt|}t|t| jj t| jj }|rft| j	j
 d| dS )z*raise an error if any dimension is missingz" does not contain the dimensions: N)r-   strr   listsetr   dimsr   r#   	__class____name__)r/   r2   r6   Zmissing_dimsr%   r%   r&   
_check_dim   s     zWeighted._check_dimNzbool | None)dar   r2   skipnar!   c                 C  s<   |dkrd}|s$|dkr.| j jdkr.| d} t| ||dS )zgreduce using dot; equivalent to (da * weights).sum(dim, skipna)

        for internal use only
        N.cfO        )r6   )r)   kindZfillnar   )r:   r   r2   r;   r%   r%   r&   _reduce   s
    
zWeighted._reduce)r:   r2   r!   c                 C  sV   |  }| jjtkr0| j|| jt|dd}n| j|| j|dd}|dk}||S )z;Calculate the sum of weights, accounting for missing valuesFr2   r;   r=   )Znotnullr   r)   boolr?   Zastypeintwhere)r/   r:   r2   masksum_of_weightsZvalid_weightsr%   r%   r&   _sum_of_weights   s     
  zWeighted._sum_of_weights)r:   r2   r;   r!   c                 C  s0   || | jj|d }| j|d | j||dS )zLReduce a DataArray by a weighted ``sum_of_squares`` along some dimension(s).r1      r@   )Zweightedr   meanr?   )r/   r:   r2   r;   Zdemeanedr%   r%   r&   _sum_of_squares   s    zWeighted._sum_of_squaresc                 C  s   | j || j||dS )zAReduce a DataArray by a weighted ``sum`` along some dimension(s).r@   )r?   r   r/   r:   r2   r;   r%   r%   r&   _weighted_sum  s    zWeighted._weighted_sumc                 C  s&   | j |||d}| j||d}|| S )zBReduce a DataArray by a weighted ``mean`` along some dimension(s).r@   r1   )rK   rF   )r/   r:   r2   r;   Zweighted_sumrE   r%   r%   r&   _weighted_mean  s    zWeighted._weighted_meanc                 C  s&   | j |||d}| j||d}|| S )zAReduce a DataArray by a weighted ``var`` along some dimension(s).r@   r1   )rI   rF   )r/   r:   r2   r;   sum_of_squaresrE   r%   r%   r&   _weighted_var  s    zWeighted._weighted_varc              	   C  s   t dt| |||S )zAReduce a DataArray by a weighted ``std`` along some dimension(s).r   )r	   npsqrtrN   rJ   r%   r%   r&   _weighted_std,  s    zWeighted._weighted_stdr
   )r:   qr2   r;   r!   c                   s6  ddddddd dddddddd	 fd
d}|dkrJ|j jdkrJd}ttj|tjd}|jdkrrtdt|dk |dkB rtd|dkr|j	}t
|r|g}tt|}t|| jdd\}}t||\}}t|||||gdggtjgtdt|iddd||dd
}|dd}|j|d }|S )zEApply a weighted ``quantile`` to a DataArray along some dimension(s).floatz
np.ndarrayQUANTILE_METHODS)nrR   methodr!   c                 S  s   |dkr| d | d }n|dkr,| | }np|dkrB| | d }nZ|dkrX| d | }nD|dkrr| d | d }n*|d	kr| d
 | d }nt d| d|d| S )z#Return the interpolation parameter.r      r   r   g      ?r   r   gUUUUUU?r   g      ?g      ?zInvalid method: .)r#   Zclip)rU   rR   rV   hr%   r%   r&   _get_h?  s    
z+Weighted._weighted_quantile.<locals>._get_hr   rA   )r*   r   rR   r;   rV   r!   c                   s$  t | }|r&| }| | } || }n| r>t |jt jS |dk}| | } || }| j}|dkrtt |jt jS | d |d   }	t | }
| |
 } ||
 }||  }t d|	 }t 
|j} |	||}t |d |	 t ||	 |}||	 | d }t |}| | jddS )Nr   rG   rW   )Zaxis)rO   isnanr"   fullsizenansumZargsortappendZcumsumZ
atleast_2dTmaximumZminimumZdiff)r*   r   rR   r;   rV   is_nanZnot_nanZnonzero_weightsrU   nwZsorterZweights_cumrY   uvr$   rZ   r%   r&   _weighted_quantile_1dR  s2    



 
z:Weighted._weighted_quantile.<locals>._weighted_quantile_1dNr<   Tr(   rW   zq must be a scalar or 1dr   z q values must be between 0 and 1inner)joinquantile)Zoutput_sizesZparallelized)rR   r;   )Zinput_core_dimsZoutput_core_dimsZoutput_dtypesZdask_gufunc_kwargsZdaskZ	vectorizekwargs.)rk   )r   )r)   r>   rO   Z
atleast_1dZasarrayZfloat64ndimr#   r"   r6   r   Z	is_scalarr	   r   r   r   r   r   dictlenZ	transposeZassign_coordsZsqueeze)r/   r:   rR   r2   r;   rh   r   resultr%   rg   r&   _weighted_quantile6  s@    	 :



zWeighted._weighted_quantilec                 K  s   t dd S )Nz.Use `Dataset.weighted` or `DataArray.weighted`)NotImplementedErrorr/   funcr2   rl   r%   r%   r&   _implementation  s    zWeighted._implementation)r2   
keep_attrsr!   c                 C  s   | j | j||dS )N)r2   rv   )ru   rF   )r/   r2   rv   r%   r%   r&   rE     s
      zWeighted.sum_of_weights)r2   r;   rv   r!   c                 C  s   | j | j|||dS N)r2   r;   rv   )ru   rI   r/   r2   r;   rv   r%   r%   r&   rM     s       zWeighted.sum_of_squaresc                 C  s   | j | j|||dS rw   )ru   rK   rx   r%   r%   r&   r_     s       zWeighted.sumc                 C  s   | j | j|||dS rw   )ru   rL   rx   r%   r%   r&   rH     s       zWeighted.meanc                 C  s   | j | j|||dS rw   )ru   rN   rx   r%   r%   r&   var  s       zWeighted.varc                 C  s   | j | j|||dS rw   )ru   rQ   rx   r%   r%   r&   std  s       zWeighted.stdT)r2   rv   r;   rA   )rR   r2   rv   r;   r!   c                C  s   | j | j||||dS )N)rR   r2   r;   rv   )ru   rq   )r/   rR   r2   rv   r;   r%   r%   r&   rk     s    	    zWeighted.quantiler3   r!   c                 C  s*   | j j}dtt| jj}| d| S )z.provide a nice str repr of our Weighted objectz, z  with weights along dimensions: )r7   r8   rj   mapr3   r   r6   )r/   klassZweight_dimsr%   r%   r&   __repr__  s    zWeighted.__repr__)NN)N)NN)NN)NN)NN)NN)NN)NN)NNN)NNN)NNN)NNN)NNN)r8   
__module____qualname____doc__	__slots__r0   r9   staticmethodr?   rF   rI   rK   rL   rN   rQ   rq   ru   rE   rM   r_   rH   ry   rz   rk   r~   r%   r%   r%   r&   r      sr   .                                r   c                   @  s   e Zd ZddddZdS )DataArrayWeightedr   r{   c                 K  s6   |  | | j }|j|fd|i|}| j|S Nr2   )r9   r   Z_to_temp_datasetr|   Z_from_temp_dataset)r/   rt   r2   rl   Zdatasetr%   r%   r&   ru     s    

z!DataArrayWeighted._implementationNr8   r   r   ru   r%   r%   r%   r&   r     s   r   r   c                   @  s   e Zd ZddddZdS )DatasetWeightedr   r{   c                 K  s"   |  | | jj|fd|i|S r   )r9   r   r|   rs   r%   r%   r&   ru   "  s    
zDatasetWeighted._implementationNr   r%   r%   r%   r&   r   !  s   r   r   c                 C  s   t j|d| j_tj|ddd| j_tj|ddd| j_tj|ddd| j_tj|ddd| j_tj|d	dd| j	_t
j|d| j_d S )
N)clsr_   0)r   ZfcnZon_zerorH   NaNrM   ry   rz   )_SUM_OF_WEIGHTS_DOCSTRINGformatrE   r   #_WEIGHTED_REDUCE_DOCSTRING_TEMPLATEr_   rH   rM   ry   rz   %_WEIGHTED_QUANTILE_DOCSTRING_TEMPLATErk   )r   Zcls_namer%   r%   r&   _inject_docstring)  s6      
  
  
  
  
r   )(
__future__r   typingr   r   r   r   r   r   r	   ZnumpyrO   Znumpy.typingr
   Zxarray.corer   r   Zxarray.core.alignmentr   r   Zxarray.core.computationr   r   Zxarray.core.pycompatr   Zxarray.core.typesr   r   rT   r   r   r   r,   r   Zxarray.core.datasetr   r   r   r   r   r%   r%   r%   r&   <module>   s4   $	8   

