U
    KvfwD                     @   s   d gZ ddlZddlmZmZmZ ddlmZ er:ddl	Z	dd Z
dd Zd	d
 ZG dd deZeeZdd Zde_dd Zdd ZdS )bs    N)have_pandasno_picklingassert_no_pickling)stateful_transformc                 C   s<  zddl m} W n tk
r,   tdY nX ttj|td}|jdksPt|	  t
|}t| } | jdkr| jd dkr| d d df } | jdkstt| t|k st| t|krtdt||d  }tj| jd |ftd}t|D ]6}t|f}d||< || |||f|d d |f< q |S )Nr   )splevz#spline functionality requires scipy)Zdtype      zksome data points fall outside the outermost knots, and I'm not sure how to handle them. (Patches accepted!))Zscipy.interpolater   ImportErrornp
atleast_1dasarrayfloatndimAssertionErrorsortintshapeminmaxNotImplementedErrorlenemptyrangezeros)xknotsdegreer   Zn_basesbasisiZcoefs r    1/tmp/pip-unpacked-wheel-68fdvdus/patsy/splines.py_eval_bspline_basis   s*    
( r"   c                    s:   t |}t  fdd|jddD }|j|jddS )Nc                    s   g | ]}t  d | qS )d   )r   Z
percentile).0probr   r    r!   
<listcomp>A   s   z&_R_compat_quantile.<locals>.<listcomp>C)order)r   r   ZravelZreshaper   )r   ZprobsZ	quantilesr    r&   r!   _R_compat_quantile>   s
    

r*   c                  C   s`   dd } | ddgdd | ddgdd | ddgdd	gdd
g | t tddd	gddg d S )Nc                 S   s   t t| ||std S N)r   Zallcloser*   r   )r   r%   expectedr    r    r!   tF   s    z"test__R_compat_quantile.<locals>.t
      g      ?   g333333?   gffffff?   g@g333333@)listr   )r-   r    r    r!   test__R_compat_quantileE   s
    r4   c                   @   s8   e Zd ZdZdd ZdddZd	d
 ZdddZeZ	dS )BSa3  bs(x, df=None, knots=None, degree=3, include_intercept=False, lower_bound=None, upper_bound=None)

    Generates a B-spline basis for ``x``, allowing non-linear fits. The usual
    usage is something like::

      y ~ 1 + bs(x, 4)

    to fit ``y`` as a smooth function of ``x``, with 4 degrees of freedom
    given to the smooth.

    :arg df: The number of degrees of freedom to use for this spline. The
      return value will have this many columns. You must specify at least one
      of ``df`` and ``knots``.
    :arg knots: The interior knots to use for the spline. If unspecified, then
      equally spaced quantiles of the input data are used. You must specify at
      least one of ``df`` and ``knots``.
    :arg degree: The degree of the spline to use.
    :arg include_intercept: If ``True``, then the resulting
      spline basis will span the intercept term (i.e., the constant
      function). If ``False`` (the default) then this will not be the case,
      which is useful for avoiding overspecification in models that include
      multiple spline terms and/or an intercept term.
    :arg lower_bound: The lower exterior knot location.
    :arg upper_bound: The upper exterior knot location.

    A spline with ``degree=0`` is piecewise constant with breakpoints at each
    knot, and the default knot positions are quantiles of the input. So if you
    find yourself in the situation of wanting to quantize a continuous
    variable into ``num_bins`` equal-sized bins with a constant effect across
    each bin, you can use ``bs(x, num_bins - 1, degree=0)``. (The ``- 1`` is
    because one degree of freedom will be taken by the intercept;
    alternatively, you could leave the intercept term out of your model and
    use ``bs(x, num_bins, degree=0, include_intercept=True)``.

    A spline with ``degree=1`` is piecewise linear with breakpoints at each
    knot.

    The default is ``degree=3``, which gives a cubic b-spline.

    This is a stateful transform (for details see
    :ref:`stateful-transforms`). If ``knots``, ``lower_bound``, or
    ``upper_bound`` are not specified, they will be calculated from the data
    and then the chosen values will be remembered and re-used for prediction
    from the fitted model.

    Using this function requires scipy be installed.

    .. note:: This function is very similar to the R function of the same
      name. In cases where both return output at all (e.g., R's ``bs`` will
      raise an error if ``degree=0``, while patsy's will not), they should
      produce identical output given identical input and parameter settings.

    .. warning:: I'm not sure on what the proper handling of points outside
      the lower/upper bounds is, so for now attempting to evaluate a spline
      basis at such points produces an error. Patches gratefully accepted.

    .. versionadded:: 0.2.0
    c                 C   s   i | _ d | _d | _d S r+   )_tmp_degree
_all_knots)selfr    r    r!   __init__   s    zBS.__init__N   Fc           	      C   sx   ||||||d}|| j d< t|}|jdkrN|jd dkrN|d d df }|jdkr`td| j dg | d S )N)dfr   r   include_interceptlower_boundupper_boundargsr	   r   r   z1input to 'bs' must be 1-d, or a 2-d column vectorxs)r6   r   r   r   r   
ValueError
setdefaultappend)	r9   r   r<   r   r   r=   r>   r?   r@   r    r    r!   memorize_chunk   s    


zBS.memorize_chunkc                 C   sf  | j }|d }| ` |d dk r0td|d f t|d |d krTtd| jf t|d }|d d kr|d d krtd	|d d
 }|d d k	rR|d | }|d s|d
7 }|dk rtd|d |d |d |d | f |d d k	r.t|d |krRtd|d |d |t|d f n$tdd
|d d
d }t||}|d d k	rh|d }|d d k	r|d }n
t	|}|d d k	r|d }	n
t
|}	||	krtd||	f t|}|jd
krtdt||k rtd|||k  |f t||	kr4td|||	k |	f t||	g| |f}
|
  |d | _|
| _d S )Nr@   r   r   z&degree must be greater than 0 (not %r)z"degree must be an integer (not %r)rA   r<   r   zmust specify either df or knotsr   r=   zHdf=%r is too small for degree=%r and include_intercept=%r; must be >= %szAdf=%s with degree=%r implies %s knots, but %s knots were providedr	   r>   r?   z#lower_bound > upper_bound (%r > %r)zknots must be 1 dimensionalz1some knot values (%s) fall below lower bound (%r)z1some knot values (%s) fall above upper bound (%r))r6   rB   r   r7   r   Zconcatenater   linspacer*   r   r   r   r   anyr   r8   )r9   tmpr@   r   r)   Zn_inner_knotsZknot_quantilesZinner_knotsr>   r?   Z	all_knotsr    r    r!   memorize_finish   s    
 










zBS.memorize_finishc           	      C   sT   t || j| j}|s(|d d dd f }trPt|tjtjfrPt|}|j|_|S )Nr   )	r"   r8   r7   r   
isinstancepandasZSeriesZ	DataFrameindex)	r9   r   r<   r   r   r=   r>   r?   r   r    r    r!   	transform   s    
zBS.transform)NNr;   FNN)NNr;   FNN)
__name__
__module____qualname____doc__r:   rE   rJ   rN   r   __getstate__r    r    r    r!   r5   M   s   :     
I     
r5   c                  C   s\  ddl m}  ddlm}m}m} |d}d}|d}|| dksHqJ|d7 }|d|}||| }i }	|D ]}
|
dd\}}||	|< qpt|	d	 t	|	d
 t	|	d d}|	d dkrt	|	d \}}||d< ||d< |	d dk|d< t
t	|	d }|d
 d k	r&|jd |d
 ks&t| td||f| |d7 }|d }q8||ksXtd S )Nr   )check_stateful)R_bs_test_xR_bs_test_dataR_bs_num_tests
z--BEGIN TEST CASE--r   z--END TEST CASE--=r   r<   r   )r   r<   r   zBoundary.knotsNoner>   r?   Z	interceptTRUEr=   outputF)Zpatsy.test_staterT   Zpatsy.test_splines_bs_datarU   rV   rW   splitrM   r   evalr   r   r   r   r5   )rT   rU   rV   rW   linesZ	tests_ranZ	start_idxZstop_idxblockZ	test_datalinekeyvaluekwargslowerupperr\   r    r    r!   test_bs_compat   s<    






rg   r   c                  C   sX  t ddd} t| ddgddd}|jd dks4tt d}d|| dk < t |d d df |sftt d}d|| dk| dk @ < t |d d df |stt d}d|| dk< t |d d d	f |stt tddd	gddgdd
ddgddgddggs
tt| ddgddd}t| ddgddd}t |d d dd f |sTtd S )NrF   r   r.      r   T)r   r   r=   r;   r	   )r   r   r=   F)r   Zlogspacer   r   r   r   array_equal)r   resultZ
expected_0Z
expected_1Z
expected_2Z
result_intZresult_no_intr    r    r!   test_bs_0degree-  s.    



rk   c               	   C   s  dd l } tddd}| jtt|ddd | jtt|ddd | tt| t|dddgd	 d
 t|dddgd d
 t|dddgd dd t|dddgd dd | jtt|dddgd d
 | jtt|dddgd	 d
 | jtt|dddgd dd | jtt|dddgd dd | jtt|dddgd d
 | jtt|dddgd d
 | jtt|dddgd dd | jtt|dddgd	 dd | jtt|ddd | jtt|ddd | jtt|ddd | jtt|ddd | jtt|dddd | ttt||fd tt|ddgdt|ddgds:t	| jtt|dgdggd | jtt|ddgd | jtt|ddgdd | jtt|ddgd | jtt|ddgdd d S )Nr   ir.   r/   r;   )r>   )r?   F   )r<   r=   r   T   	   r   )r<   r=   r   r         )r<   r   rF   g      ?)r>   r?   rh   )r   )r   r?   i)r   r>   )
pytestr   rG   Zraisesr   r   rB   Zcolumn_stackri   r   )rs   r   r    r    r!   test_bs_errorsH  s
                                                     *  
          rt   )__all__Znumpyr   Z
patsy.utilr   r   r   Zpatsy.stater   rL   r"   r*   r4   objectr5   r   rg   Zslowrk   rt   r    r    r    r!   <module>   s   , .-