B
    ZP                 @   sT  d Z ddlmZ ddlZddlmZ ddlmZ ddl	m
Z ddlmZ dd	 Zd0ddZd1ddZd2ddZd3ddZdd Zdd ZG dd deZG dd deZedkrPeddgddggddgddgggZeddgddggddgd dgggZeddgddggdd!gd dgggZeddgddggddgd!dggd"dgd d"gggZejed#dddddf d$ed#dddddf  f Z edddgdddgdddggd$ddgd d%dgddd&gggZ!ej"#d'd(Z$eee$Z%ej&j'ee%d
e%d)d*Z(e(d )d
d(d(Z*ee*Z+ee%Z,e,-d
 e,.  e,.d+d,d  eddgddggddgd!dggd"dgd d"gggZ/eddgddggd-dgd!d.gggZ0eddgddggd/dgd-dggd.dgd d"gggZ1ee/e0Z2e3e4e2 e3e25  e3e25e e3e26  e3e27  e3e28  ee1Z9e3e97  e3e98  dS )4a8   Helper and filter functions for VAR and VARMA, and basic VAR class

Created on Mon Jan 11 11:04:23 2010
Author: josef-pktd
License: BSD

This is a new version, I didn't look at the old version again, but similar
ideas.

not copied/cleaned yet:
 * fftn based filtering, creating samples with fft
 * Tests: I ran examples but did not convert them to tests
   examples look good for parameter estimate and forecast, and filter functions

main TODOs:
* result statistics
* see whether Bayesian dummy observation can be included without changing
  the single call to linalg.lstsq
* impulse response function does not treat correlation, see Hamilton and jplv

Extensions
* constraints, Bayesian priors/penalization
* Error Correction Form and Cointegration
* Factor Models Stock-Watson,  ???


see also VAR section in Notes.txt

    )print_functionN)assert_equal)signal)	_centered)lagmatc       	      C   sf  t | } t |}| jdkr.| dddf } | jdkr@td| jd }|jd }|d }|jdkrtj| |dddf ddS |jdkrt|jdkrtj| |ddS t | jd | d |f}xDt	|D ]8}tj| dd|f |dd|f dd|dd|f< qW |S |jdkrbt| dddddf |}||| |jd d ddf }|S dS )	a  apply an autoregressive filter to a series x

    Warning: I just found out that convolve doesn't work as I
       thought, this likely doesn't work correctly for
       nvars>3


    x can be 2d, a can be 1d, 2d, or 3d

    Parameters
    ----------
    x : array_like
        data array, 1d or 2d, if 2d then observations in rows
    a : array_like
        autoregressive filter coefficients, ar lag polynomial
        see Notes

    Returns
    -------
    y : ndarray, 2d
        filtered array, number of columns determined by x and a

    Notes
    -----

    In general form this uses the linear filter ::

        y = a(L)x

    where
    x : nobs, nvars
    a : nlags, nvars, npoly

    Depending on the shape and dimension of a this uses different
    Lag polynomial arrays

    case 1 : a is 1d or (nlags,1)
        one lag polynomial is applied to all variables (columns of x)
    case 2 : a is 2d, (nlags, nvars)
        each series is independently filtered with its own
        lag polynomial, uses loop over nvar
    case 3 : a is 3d, (nlags, nvars, npoly)
        the ith column of the output array is given by the linear filter
        defined by the 2d array a[:,:,i], i.e. ::

            y[:,i] = a(.,.,i)(L) * x
            y[t,i] = sum_p sum_j a(p,j,i)*x(t-p,j)
                     for p = 0,...nlags-1, j = 0,...nvars-1,
                     for all t >= nlags


    Note: maybe convert to axis=1, Not

    TODO: initial conditions

       N   zx array has to be 1d or 2dr   Zvalid)mode   )
npZasarrayndim
ValueErrorshaper   Zconvolveminzerosrange)	xanvarnlagsZntrimresultiZyfZyvalid r   <lib/python3.7/site-packages/statsmodels/tsa/varma_process.py	varfilter)   s,    9






8"r   r   c       
      C   s\  | j \}}}||krtd t|d ||f}| d |dddddf< | dd  |d|ddddf< |dkrxztd|d D ]h}t||f}x>td|D ]0}	|t| |	  |||	 ddddf 7 }qW |||ddddf< qW |dkrXxZt|d |d D ]D}t| dd j ||d || dddddf j  tdqW |S )a  creates inverse ar filter (MA representation) recursively

    The VAR lag polynomial is defined by ::

        ar(L) y_t = u_t  or
        y_t = -ar_{-1}(L) y_{t-1} + u_t

    the returned lagpolynomial is arinv(L)=ar^{-1}(L) in ::

        y_t = arinv(L) u_t



    Parameters
    ----------
    ar : array, (nlags,nvars,nvars)
        matrix lagpolynomial, currently no exog
        first row should be identity

    Returns
    -------
    arinv : array, (nobs,nvars,nvars)


    Notes
    -----

    z.exogenous variables not implemented not testedr   r   Nr   z+waiting for generalized ufuncs or something)r   printr   r   r   dotNotImplementedError)
arnobsversionr   nvarsnvarsexZarinvr   Ztmppr   r   r   varinversefilter   s"    $0
6r%   c             C   s  | j \}}}|d }|j d }||kr.td |j d |krDtd|dkrdt|| |f}|}	n8t||j d }	t||	 |f}|||	|j d  |	< |||	d< xXt|	|	| D ]F}
x@td|D ]2}||
  t||
| ddf | |  7  < qW qW |S )aE  generate an VAR process with errors u

    similar to gauss
    uses loop

    Parameters
    ----------
    ar : array (nlags,nvars,nvars)
        matrix lagpolynomial
    u : array (nobs,nvars)
        exogenous variable, error term for VAR

    Returns
    -------
    sar : array (1+nobs,nvars)
        sample of var process, inverse filtered u
        does not trim initial condition y_0 = 0

    Examples
    --------
    # generate random sample of VAR
    nobs, nvars = 10, 2
    u = numpy.random.randn(nobs,nvars)
    a21 = np.array([[[ 1. ,  0. ],
                     [ 0. ,  1. ]],

                    [[-0.8,  0. ],
                     [ 0.,  -0.6]]])
    vargenerate(a21,u)

    # Impulse Response to an initial shock to the first variable
    imp = np.zeros((nobs, nvars))
    imp[0,0] = 1
    vargenerate(a21,imp)

    r   r   z.exogenous variables not implemented not testedzu needs to have nvars columnsN)r   r   r   r   r   maxr   r   )r   u
initvaluesr   r"   r#   Znlagsm1r    Zsarstartr   r$   r   r   r   vargenerate   s$    %
6r*   c       	         s   t | j}||  || 7  < t | j}t |}|| t | j||< |   fddtt D }| |t	|< |S )a  pad with zeros along one axis, currently only axis=0


    can be used sequentially to pad several axis

    Examples
    --------
    >>> padone(np.ones((2,3)),1,3,axis=1)
    array([[ 0.,  1.,  1.,  1.,  0.,  0.,  0.],
           [ 0.,  1.,  1.,  1.,  0.,  0.,  0.]])

    >>> padone(np.ones((2,3)),1,1, fillvalue=np.nan)
    array([[ NaN,  NaN,  NaN],
           [  1.,   1.,   1.],
           [  1.,   1.,   1.],
           [ NaN,  NaN,  NaN]])
    c                s   g | ]}t |  | qS r   )slice).0k)endindstartindr   r   
<listcomp>  s    zpadone.<locals>.<listcomp>)
r   arrayr   emptyZfillr   r   r   lentuple)	r   frontbackaxis	fillvaluer   shapearroutmyslicer   )r.   r/   r   padone   s    

r<   c                sp   t | j}||  || 8  < t | j}t | j||< |   fddtt D }| t| S )a;  trim number of array elements along one axis


    Examples
    --------
    >>> xp = padone(np.ones((2,3)),1,3,axis=1)
    >>> xp
    array([[ 0.,  1.,  1.,  1.,  0.,  0.,  0.],
           [ 0.,  1.,  1.,  1.,  0.,  0.,  0.]])
    >>> trimone(xp,1,3,1)
    array([[ 1.,  1.,  1.],
           [ 1.,  1.,  1.]])
    c                s   g | ]}t |  | qS r   )r+   )r,   r-   )r.   r/   r   r   r0   0  s    ztrimone.<locals>.<listcomp>)r   r1   r   r   r   r   r3   r4   )r   r5   r6   r7   r   r9   r;   r   )r.   r/   r   trimone  s    r=   c             C   s6   | j \}}}tjt||dddddf |  f S )z?make reduced lagpolynomial into a right side lagpoly array
    N)r   r   r_eye)r   r   r   Znvarexr   r   r   ar2full8  s    r@   c             C   s   | dd  S )zconvert full (rhs) lagpolynomial into a reduced, left side lagpoly array

    this is mainly a reminder about the definition
    r   Nr   )r   r   r   r   ar2lhs>  s    rA   c               @   s:   e Zd ZdZdd Zdd Zdd Zdd	 ZdddZdS )_Vara<  obsolete VAR class, use tsa.VAR instead, for internal use only


    Examples
    --------

    >>> v = Var(ar2s)
    >>> v.fit(1)
    >>> v.arhat
    array([[[ 1.        ,  0.        ],
            [ 0.        ,  1.        ]],

           [[-0.77784898,  0.01726193],
            [ 0.10733009, -0.78665335]]])

    c             C   s   || _ |j\| _| _d S )N)yr   r    r"   )selfrC   r   r   r   __init__Y  s    z_Var.__init__c             C   s   || _ | j}t| j|ddd}|ddd|f | _|dd|df | _tjj| j| jdd}|| _	|d 
|||| _t| j| _|d | _|d	 | _dS )
a  estimate parameters using ols

        Parameters
        ----------
        nlags : integer
            number of lags to include in regression, same for all variables

        Returns
        -------
        None, but attaches

        arhat : array (nlags, nvar, nvar)
            full lag polynomial array
        arlhs : array (nlags-1, nvar, nvar)
            reduced lag polynomial for left hand side
        other statistics as returned by linalg.lstsq : need to be completed



        This currently assumes all parameters are estimated without restrictions.
        In this case SUR is identical to OLS

        estimation results are attached to the class instance


        Zbothin)ZtrimZoriginalNr   )rcondr   r   r   )r   r"   r   rC   Zyredxredr   linalglstsqZ
estresultsreshapeZarlhsr@   arhatrssZxredrank)rD   r   r"   Zlmatresr   r   r   fit^  s    
z_Var.fitc             C   s    t | dst| j| j| _| jS )z:calculate estimated timeseries (yhat) for sample

        yhat)hasattrr   rC   rL   rP   )rD   r   r   r   predict  s    
z_Var.predictc             C   sF   | j ddddf tjt| jj| jdddddf  | _dS )a   covariance matrix of estimate
        # not sure it's correct, need to check orientation everywhere
        # looks ok, display needs getting used to
        >>> v.rss[None,None,:]*np.linalg.inv(np.dot(v.xred.T,v.xred))[:,:,None]
        array([[[ 0.37247445,  0.32210609],
                [ 0.1002642 ,  0.08670584]],

               [[ 0.1002642 ,  0.08670584],
                [ 0.45903637,  0.39696255]]])
        >>>
        >>> v.rss[0]*np.linalg.inv(np.dot(v.xred.T,v.xred))
        array([[ 0.37247445,  0.1002642 ],
               [ 0.1002642 ,  0.45903637]])
        >>> v.rss[1]*np.linalg.inv(np.dot(v.xred.T,v.xred))
        array([[ 0.32210609,  0.08670584],
               [ 0.08670584,  0.39696255]])
       N)rM   r   rI   invr   rH   TZparamcov)rD   r   r   r   covmat  s    z_Var.covmatr   Nc             C   s*   |dkrt || jf}t| j|| jdS )a  calculates forcast for horiz number of periods at end of sample

        Parameters
        ----------
        horiz : int (optional, default=1)
            forecast horizon
        u : array (horiz, nvars)
            error term for forecast periods. If None, then u is zero.

        Returns
        -------
        yforecast : array (nobs+horiz, nvars)
            this includes the sample and the forecasts
        N)r(   )r   r   r"   r*   rL   rC   )rD   Zhorizr'   r   r   r   forecast  s    z_Var.forecast)r   N)	__name__
__module____qualname____doc__rE   rO   rR   rU   rV   r   r   r   r   rB   G  s   )	rB   c               @   sd   e Zd ZdZdddZdddZddd	ZdddZdd Zdd Z	dddZ
dddZdd ZdS )	VarmaPolya  class to keep track of Varma polynomial format


    Examples
    --------

    ar23 = np.array([[[ 1. ,  0. ],
                     [ 0. ,  1. ]],

                    [[-0.6,  0. ],
                     [ 0.2, -0.6]],

                    [[-0.1,  0. ],
                     [ 0.1, -0.1]]])

    ma22 = np.array([[[ 1. ,  0. ],
                     [ 0. ,  1. ]],

                    [[ 0.4,  0. ],
                     [ 0.2, 0.3]]])


    Nc             C   s   || _ || _|j\}}}|||  | _| _| _|dd |f t|k  | _	| jd krrt|d | _d| _
n|d t|k  | _
|jd | _||k| _|dd   | _d S )Nr   )N.Tr   )r   mar   r   nvarallr"   r   r?   allisstructuredisindependentZmalagsZhasexogZarm1)rD   r   r\   r   r]   r"   r   r   r   rE     s    "

zVarmaPoly.__init__r   c             C   sD   |dk	r|}n(|dkr| j }n|dkr.| j}ntd|d| jS )z4stack lagpolynomial vertically in 2d array

        Nr   r\   zno array or name givenr   )r   r\   r   rK   r]   )rD   r   namer   r   r   vstack  s    zVarmaPoly.vstackc             C   sN   |dk	r|}n(|dkr| j }n|dkr.| j}ntd|ddd| jjS )z6stack lagpolynomial horizontally in 2d array

        Nr   r\   zno array or name givenr   r   r   )r   r\   r   swapaxesrK   r]   rT   )rD   r   ra   r   r   r   hstack  s    zVarmaPoly.hstackverticalc             C   st   |dk	r|}n(|dkr| j }n|dkr.| j}ntd|d| j}|j\}}tj||d}||ddd|f< |S )zDstack lagpolynomial vertically in 2d square array with eye

        Nr   r\   zno array or name givenr   )r-   )r   r\   r   rK   r]   r   r   r?   )rD   r   ra   ZorientationZastackedZlenpkr"   amatr   r   r   stacksquare  s    
zVarmaPoly.stacksquarec             C   s2   t | jdd | jdd fd}|d| jS )z;stack ar and lagpolynomial vertically in 2d array

        r   Nr   r   )r   concatenater   r\   rK   r]   )rD   r   r   r   r   vstackarma_minus1  s    $zVarmaPoly.vstackarma_minus1c             C   s:   t | jdd | jdd fd}|ddd| jS )zustack ar and lagpolynomial vertically in 2d array

        this is the Kalman Filter representation, I think
        r   Nr   r   r   )r   rh   r   r\   rc   rK   r]   )rD   r   r   r   r   hstackarma_minus1  s    $zVarmaPoly.hstackarma_minus1c             C   sz   |dk	r|}n.| j r,| | jdd  }n| jdd  }| |}ttj|ddd }|| _t	|dk 
 S )aA  check whether the auto-regressive lag-polynomial is stationary

        Returns
        -------
        isstationary : boolean

        *attaches*

        areigenvalues : complex array
            eigenvalues sorted by absolute value

        References
        ----------
        formula taken from NAG manual

        Nr   r   )r_   
reduceformr   rg   r   sortrI   eigvalsZareigenvaluesabsr^   )rD   r   rf   evr   r   r   getisstationary%  s    
zVarmaPoly.getisstationaryc             C   s   |dk	r|}n*| j r*| | jdd }n| jdd }|jd dkrZtg tj| _dS | |}t	tj
|ddd }|| _t|dk  S )aA  check whether the auto-regressive lag-polynomial is stationary

        Returns
        -------
        isinvertible : boolean

        *attaches*

        maeigenvalues : complex array
            eigenvalues sorted by absolute value

        References
        ----------
        formula taken from NAG manual

        Nr   r   Tr   )r`   rk   r\   r   r   r1   complexZmaeigenvaluesrg   rl   rI   rm   rn   r^   )rD   r   rf   ro   r   r   r   getisinvertibleB  s    
zVarmaPoly.getisinvertiblec             C   s   |j dkrtd|j\}}}t|}y"tj|dd|ddf }W n" tjjk
rl   tddY nX x$t|D ]}t	||| ||< qxW |S )z.

        this assumes no exog, todo

        r
   zapoly needs to be 3dr   Nzmatrix not invertiblezask for implementation of pinv)
r   r   r   r   Z
empty_likerI   rS   ZLinAlgErrorr   r   )rD   Zapolyr   r#   r"   r   Za0invZlagr   r   r   rk   e  s    

"zVarmaPoly.reduceform)N)Nr   )Nr   )Nr   re   )N)N)rW   rX   rY   rZ   rE   rb   rd   rg   ri   rj   rp   rr   rk   r   r   r   r   r[     s   





#r[   __main__g      ?g        gg333333g?g?gr
   g?g333333?g?i  r   r   )rG      ig?g333333?gffffff)r   )N)r   r   r   r   )r   r   r   ):rZ   Z
__future__r   Znumpyr   Znumpy.testingr   Zscipyr   Zscipy.signal.signaltoolsr   Ztrim_centeredZstatsmodels.tsa.tsatoolsr   r   r%   r*   r<   r=   r@   rA   objectrB   r[   rW   r1   Za21Za22Za23Za24r>   r?   Za31Za32ZrandomZrandnutZar2srI   rJ   rN   rK   ZbhatrL   vrO   rV   Zar23Zma22Zar23nsZvpr   varsrb   rj   rp   rr   Zvp2r   r   r   r   <module>   s   `
3
=
"
	t D




B






