a
    \:bE                     @   s,  d Z ddlmZmZmZ ddlZedZG dd de	Z
G dd de	ZG d	d
 d
e	Zeejd ZG dd de	ZdOddZdPddZdQddZG dd de	ZdRddZedkr(g dZdZddlmZ ddlmZmZ eddd ed!d"d fZ ed#d$geej!ej!ge d%Z"e Z#d&ev rbe"e"d'ke"dk @  d Z"ee"ed(dd)\Z$Z%Z&Z'e$Z(e)e$e%Z*e+d*e$,  e$e$,  Z$e)e$e%Z-e+d+e*e- e$e- Z$dZ.e.rej/e"d,d-d.d/ ej0e%e$dd0d1 ej0e%e(dd2d1 e1  e2e'dd D ]D\Z3Z4e2e'dd D ](\Z5Z6e+e3e5e7d3d4 d5d!d  qqe'D ]Z4e+e7d6d4 d5d! qDd7ev r,e j8e"ed(d8Z9e:e", e"; Z%e9e%Z<ej7e9ge9j=R  d Z>e+d9e> e#j?e%d#d$gej!ej!ge d:Z@d!Z.e.r,eA  ej/e"d,d-d.d/ ej0e%e<dd0d1 ej0e%e@dd;d1 eBd< d=ev r4e Z9de9_Ce9j8e"ed>d8Z9e:e", e"; Z%e9e%Z<ej7e9ge9j=R  d Z>e+d9e> e#j?e%d#d$gej!ej!ge d:Z@d!Z.e.r eA  ej/e"d,d-d.d/ eBd? ej0e%e<dd0d1 ej0e%e@dd;d1 e+e;eDee9j'dd dd!d eEd  d@ev rDe Z9de9_Ce9j8e"ed(d8Z9e:e", e"; Z%e9e%Z<ej7e9ge9j=R  d Z>e+d9e> e#j?e%d#d$gej!ej!ge d:Z@d!Z.e.reA  ej/e"d,d-d.d/ ej0e%e<dd0d1 ej0e%e@dd;d1 eBdA e1  e+e;eDee9j'dd dd!d eEd  dBdC eFdD ZGeeGdDdEd ZHe+e;eDeHeEd  e+eHdF IeJ ddGlKmLZLmMZM dHdC eFdD ZNeeNdIdJd ZOe+eOdF IeJ dKdC eFdLD ZPeePd5d!dMd4 dN\ZQZRe+e;eDeQeSeSeQ  dS )Sa  density estimation based on orthogonal polynomials


Author: Josef Perktold
Created: 2011-05017
License: BSD

2 versions work: based on Fourier, FPoly, and chebychev T, ChebyTPoly
also hermite polynomials, HPoly, works
other versions need normalization


TODO:

* check fourier case again:  base is orthonormal,
  but needs offsetfact = 0 and does not integrate to 1, rescaled looks good
* hermite: works but DensityOrthoPoly requires currently finite bounds
  I use it with offsettfactor 0.5 in example
* not implemented methods:
  - add bonafide density correction
  - add transformation to domain of polynomial base - DONE
    possible problem: what is the behavior at the boundary,
    offsetfact requires more work, check different cases, add as option
    moved to polynomial class by default, as attribute
* convert examples to test cases
* need examples with large density on boundary, beta ?
* organize poly classes in separate module, check new numpy.polynomials,
  polyvander
* MISE measures, order selection, ...

enhancements:
  * other polynomial bases: especially for open and half open support
  * wavelets
  * local or piecewise approximations


    )stats	integratespecialN       @c                   @   s    e Zd ZdZdd Zdd ZdS )FPolyaB  Orthonormal (for weight=1) Fourier Polynomial on [0,1]

    orthonormal polynomial but density needs corfactor that I do not see what
    it is analytically

    parameterization on [0,1] from

    Sam Efromovich: Orthogonal series density estimation,
    2010 John Wiley & Sons, Inc. WIREs Comp Stat 2010 2 467-476


    c                 C   s   || _ d| _| j| _d S )N)r      )orderdomain	intdomainselfr    r   Qlib/python3.9/site-packages/statsmodels/sandbox/nonparametric/densityorthopoly.py__init__=   s    zFPoly.__init__c                 C   s2   | j dkrt|S tttj| j  |  S d S Nr   )r   np	ones_likesqr2cospir   xr   r   r   __call__B   s    

zFPoly.__call__N__name__
__module____qualname____doc__r   r   r   r   r   r   r   /   s   r   c                   @   s    e Zd ZdZdd Zdd ZdS )F2Polya  Orthogonal (for weight=1) Fourier Polynomial on [0,pi]

    is orthogonal but first component does not square-integrate to 1
    final result seems to need a correction factor of sqrt(pi)
    _corfactor = sqrt(pi) from integrating the density

    Parameterization on [0, pi] from

    Peter Hall, Cross-Validation and the Smoothing of Orthogonal Series Density
    Estimators, JOURNAL OF MULTIVARIATE ANALYSIS 21, 189-206 (1987)

    c                 C   s$   || _ dtjf| _| j| _d| _d S r   )r   r   r   r	   r
   offsetfactorr   r   r   r   r   V   s    zF2Poly.__init__c                 C   sD   | j dkr t|ttj S tt| j |  ttj S d S r   )r   r   r   sqrtr   r   r   r   r   r   r   r   \   s    
zF2Poly.__call__Nr   r   r   r   r   r   H   s   r   c                   @   s    e Zd ZdZdd Zdd ZdS )
ChebyTPolyaL  Orthonormal (for weight=1) Chebychev Polynomial on (-1,1)


    Notes
    -----
    integration requires to stay away from boundary, offsetfactor > 0
    maybe this implies that we cannot use it for densities that are > 0 at
    boundary ???

    or maybe there is a mistake close to the boundary, sometimes integration works.

    c                 C   s2   || _ ddlm} ||| _d| _d| _d| _d S )Nr   chebyt)r   )g!g!?g{Gz?)r   scipy.specialr#   polyr	   r
   r   )r   r   r#   r   r   r   r   p   s    
zChebyTPoly.__init__c                 C   sd   | j dkr0t|d|d  d  ttj S | |d|d  d  ttj td S d S )Nr   r      g      ?)r   r   r   r    r   r&   r   r   r   r   r   z   s    
&zChebyTPoly.__call__Nr   r   r   r   r   r!   b   s   
r!   r'   c                   @   s    e Zd ZdZdd Zdd ZdS )HPolyzOrthonormal (for weight=1) Hermite Polynomial, uses finite bounds

    for current use with DensityOrthoPoly domain is defined as [-6,6]

    c                 C   s,   || _ ddlm} ||| _d| _d| _d S )Nr   hermite)         ?)r   r%   r*   r&   r	   r   )r   r   r*   r   r   r   r      s
    
zHPoly.__init__c                 C   sN   | j }d|td t|d  t  || d  }t|}| || S )N      r   r   r'   )r   r   logr   Zgammalnlogpi2Zexpr&   )r   r   kZlnfactZfactr   r   r   r      s    0
zHPoly.__call__Nr   r   r   r   r   r(      s   r(      c                    s"   t  fddt|D }|S )Nc                    s   g | ]} |qS r   r   .0ipolybaser   r   r   
<listcomp>       zpolyvander.<locals>.<listcomp>)r   Zcolumn_stackrange)r   r7   r   Zpolyarrr   r6   r   
polyvander   s    r;   c                    s   t | }t||f}|tj t||f}t|D ]}t|d D ]}| |  | | durt fdd||\}	}
nt fdd||\}	}
|	|||f< |
|||f< ||ksH|	|||f< |
|||f< qHq8||fS )a  inner product of continuous function (with weight=1)

    Parameters
    ----------
    polys : list of callables
        polynomial instances
    lower : float
        lower integration limit
    upper : float
        upper integration limit
    weight : callable or None
        weighting function

    Returns
    -------
    innp : ndarray
        symmetric 2d square array with innerproduct of all function pairs
    err : ndarray
        numerical error estimate from scipy.integrate.quad, same dimension as innp

    Examples
    --------
    >>> from scipy.special import chebyt
    >>> polys = [chebyt(i) for i in range(4)]
    >>> r, e = inner_cont(polys, -1, 1)
    >>> r
    array([[ 2.        ,  0.        , -0.66666667,  0.        ],
           [ 0.        ,  0.66666667,  0.        , -0.4       ],
           [-0.66666667,  0.        ,  0.93333333,  0.        ],
           [ 0.        , -0.4       ,  0.        ,  0.97142857]])

    r   Nc                    s    | |  |  S Nr   r   p1p2weightr   r   <lambda>   r9   zinner_cont.<locals>.<lambda>c                    s    | |  S r<   r   r=   r?   r@   r   r   rB      r9   )	lenr   emptyZfillnanZzerosr:   r   quad)polyslowerupperrA   Zn_polys	innerprodZinterrr5   jZinnperrr   r>   r   
inner_cont   s&    !
rN   :0yE>c                    sr   t t| D ]`}t |d D ]N}| |  | | t fdd||d }tj|||k||ds  dS qqdS )aZ  check whether functions are orthonormal

    Parameters
    ----------
    polys : list of polynomials or function

    Returns
    -------
    is_orthonormal : bool
        is False if the innerproducts are not close to 0 or 1

    Notes
    -----
    this stops as soon as the first deviation from orthonormality is found.

    Examples
    --------
    >>> from scipy.special import chebyt
    >>> polys = [chebyt(i) for i in range(4)]
    >>> r, e = inner_cont(polys, -1, 1)
    >>> r
    array([[ 2.        ,  0.        , -0.66666667,  0.        ],
           [ 0.        ,  0.66666667,  0.        , -0.4       ],
           [-0.66666667,  0.        ,  0.93333333,  0.        ],
           [ 0.        , -0.4       ,  0.        ,  0.97142857]])
    >>> is_orthonormal_cont(polys, -1, 1, atol=1e-6)
    False

    >>> polys = [ChebyTPoly(i) for i in range(4)]
    >>> r, e = inner_cont(polys, -1, 1)
    >>> r
    array([[  1.00000000e+00,   0.00000000e+00,  -9.31270888e-14,
              0.00000000e+00],
           [  0.00000000e+00,   1.00000000e+00,   0.00000000e+00,
             -9.47850712e-15],
           [ -9.31270888e-14,   0.00000000e+00,   1.00000000e+00,
              0.00000000e+00],
           [  0.00000000e+00,  -9.47850712e-15,   0.00000000e+00,
              1.00000000e+00]])
    >>> is_orthonormal_cont(polys, -1, 1, atol=1e-6)
    True

    r   c                    s    | |  S r<   r   r=   rC   r   r   rB     r9   z%is_orthonormal_cont.<locals>.<lambda>r   )rtolatolFT)r:   rD   r   rG   r   Zallclose)rH   rI   rJ   rP   rQ   r5   rL   rK   r   rC   r   is_orthonormal_cont   s    ,rR   c                   @   sN   e Zd ZdZdddZdddZddd	Zd
d Zdd Zdd Z	dd Z
dS )DensityOrthoPolya  Univariate density estimation by orthonormal series expansion


    Uses an orthonormal polynomial basis to approximate a univariate density.


    currently all arguments can be given to fit, I might change it to requiring
    arguments in __init__ instead.
    Nr2   c                    s:    d ur* | _  fddt|D  | _}d| _d| _d S )Nc                    s   g | ]} |qS r   r   r3   r7   r   r   r8     r9   z-DensityOrthoPoly.__init__.<locals>.<listcomp>r   r   )r7   r:   rH   
_corfactor	_corshift)r   r7   r   rH   r   rT   r   r     s
    zDensityOrthoPoly.__init__c                    s   du r| j d| }n" | _ fddt|D  | _ }t| dsP|d j| _   }}|du r|| | j  | _}|| || f }| _	|d |d  }	|| }
d|	 | _
|	|
 d }|| | _|  | _fd	d|D }|| _|| _ |   | S )
zIestimate the orthogonal polynomial approximation to the density

        Nc                    s   g | ]} |qS r   r   r3   rT   r   r   r8   .  r9   z(DensityOrthoPoly.fit.<locals>.<listcomp>	offsetfacr   r         ?r   c                    s   g | ]}|   qS r   Zmeanr4   pr=   r   r   r8   C  r9   )rH   r7   r:   hasattrr   rW   minmaxoffsetlimitsshrinkshift
_transformr   coeffs_verify)r   r   r7   r   r`   rH   ZxminZxmaxr_   Zinterval_lengthZ	xintervalrd   r   r6   r   fit&  s*    


zDensityOrthoPoly.fitc                    sV   |    |d u rt| j}t fddtt| j| jd | D }| |}|S )Nc                 3   s   | ]\}}||  V  qd S r<   r   r4   cr[   xevalr   r   	<genexpr>N  r9   z,DensityOrthoPoly.evaluate.<locals>.<genexpr>)rc   rD   rH   sumlistziprd   _correction)r   rj   r   resr   ri   r   evaluateJ  s    

,
zDensityOrthoPoly.evaluatec                 C   s
   |  |S )z,alias for evaluate, except no order argument)rq   )r   rj   r   r   r   r   R  s    zDensityOrthoPoly.__call__c                 C   s*   | j }dtj| jg|R  d  | _| jS )zcheck for bona fide density correction

        currently only checks that density integrates to 1

`       non-negativity - NotImplementedYet
        rX   r   )r`   r   rG   rq   rU   )r   r
   r   r   r   re   V  s    
zDensityOrthoPoly._verifyc                 C   s,   | j dkr|| j 9 }| jdkr(|| j7 }|S )zhbona fide density correction

        affine shift of density to make it into a proper density

        r   r   )rU   rV   r   r   r   r   ro   h  s
    



zDensityOrthoPoly._correctionc                 C   sJ   | j d j}|d |d  }| j|d | j |  }| j| }|| | S )ztransform observation to the domain of the density


        uses shrink and shift attribute which are set in fit to stay


        r   r   )rH   r	   rb   ra   )r   r   r	   Zilenrb   ra   r   r   r   rc   v  s
    
zDensityOrthoPoly._transform)Nr2   )Nr2   N)N)r   r   r   r   r   rf   rq   r   re   ro   rc   r   r   r   r   rS     s   


$
rS   c                    sn   d u rt   d fddt|D }fdd|D }tfddt||D }|||fS )N2   c                    s   g | ]} |qS r   r   r3   rT   r   r   r8     r9   z%density_orthopoly.<locals>.<listcomp>c                    s   g | ]}|   qS r   rY   rZ   r=   r   r   r8     r9   c                 3   s   | ]\}}||  V  qd S r<   r   rg   ri   r   r   rk     r9   z$density_orthopoly.<locals>.<genexpr>)r   linspacer]   r^   r:   rl   rn   )r   r7   r   rj   rH   rd   rp   r   )r7   r   rj   r   density_orthopoly  s    rt   __main__)r#   fourierr*   i'  )mixture_rvsMixtureDistributionr.   r-   )ZlocZscaler   g?gUUUUUU?gUUUUUU?)sizedistkwargsZchebyt_   )r   rj   zf_hat.min()fint2rr   TZred)ZbinsZnormedcolorZblack)Zlwr   gc                 C   s   t | t|  S r<   )r[   r@   r=   r   r   r   rB     r9   rB   r$   c                 C   s   t | d S )Nr'   )r[   r=   r   r   r   rB     r9   r#   )r   zdop F integral)rz   r{   Zgreenzusing Chebychev polynomialsrv      zusing Fourier polynomialsr*   zusing Hermite polynomialsc                 C   s   g | ]}t |qS r   )r(   r3   r   r   r   r8   %  r9   r8   r+   r,   i )r*   r#   c                 C   s   g | ]}t |qS r   r)   r3   r   r   r   r8   +  r9   i
   c                 C   s   g | ]}t |qS r   r"   r3   r   r   r   r8   /  r9      c                 C   s   d| |   d S )Nr   r.   r   r=   r   r   r   rB   0  r9   )rA   )r2   )N)r   rO   )r2   N)Tr   Zscipyr   r   r   Znumpyr   r    r   objectr   r   r!   r/   r   r0   r(   r;   rN   rR   rS   rt   r   ZexamplesZnobsZmatplotlib.pyplotZpyplotZpltZ%statsmodels.distributions.mixture_rvsrw   rx   dictZmix_kwdsZnormZobs_distZmixZf_hatZgridrd   rH   Zf_hat0ZtrapzZfintprintr]   r~   ZdoplotZhistZplotZshow	enumerater5   r[   rL   r@   rG   rf   Zdoprs   r^   Zxfr`   ZdopintZpdfZmpdfZfiguretitlerW   absZeyer:   ZhpolysZinnZastypeintr%   r*   r#   ZhtpolysZinntZpolyscreZdiagr   r   r   r   <module>   s   %
 

8
;{


&





4


4