B
    ^{UZD                 @   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@  y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}xBt|D ]6}t|f}d||< || |||f|d d |f< qW |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    ,lib/python3.7/site-packages/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%   Z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
    r1   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 )N)_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)r3   r   r   r   r   
ValueError
setdefaultappend)	r6   r   r9   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)r>   r9   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))r3   r?   r   r4   r   Zconcatenater   linspacer)   r   r   r   r   anyr   r5   )r6   Ztmpr=   r   r(   Zn_inner_knotsZknot_quantilesZinner_knotsr;   r<   Z	all_knotsr    r    r!   memorize_finish   sp    











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"   r5   r4   r   
isinstancepandasZSeriesZ	DataFrameindex)	r6   r   r9   r   r   r:   r;   r<   r   r    r    r!   	transform   s    
zBS.transform)NNr8   FNN)NNr8   FNN)
__name__
__module____qualname____doc__r7   rB   rF   rJ   r   __getstate__r    r    r    r!   r2   M   s   :  
I  

r2   c              C   sd  ddl m}  ddlm}m}m} |d}d}|d}x|| dksJP |d7 }|d|}||| }i }	x$|D ]}
|
dd\}}||	|< qtW t|	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 }q<W ||ks`t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   r9   r   )r   r9   r   zBoundary.knotsNoner;   r<   Z	interceptZTRUEr:   outputF)Zpatsy.test_staterP   Zpatsy.test_splines_bs_datarQ   rR   rS   splitrI   r   evalr   r   r   r   r2   )rP   rQ   rR   rS   linesZ	tests_ranZ	start_idxZstop_idxblockZ	test_datalinekeyvaluekwargslowerupperrW   r    r    r!   test_bs_compat   s<    




rb   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 )NrC   r   r+      r   T)r   r   r:   r8   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(    


rf   c           	   C   s  ddl m}  tddd}| tt|ddd | 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 | tt|dd	dgd d | tt|dddgd
 d | tt|dd	dgd dd | tt|dddgd dd | tt|dd	dgd d | tt|dddgd d | tt|dd	dgd dd | tt|dddgd
 dd | tt|ddd | tt|ddd | tt|ddd | tt|ddd | tt|dddd | ttt||fd tt|ddgdt|ddgdst	| tt|dgdggd | tt|ddgd | tt|ddgdd | tt|ddgd | tt|ddgdd d S )Nr   )assert_raisesir+   r,   r8   )r;   )r<   F   )r9   r:   r   T   	   r   )r9   r:   r   r         )r9   r   rC   g      ?)r;   r<   rc   )r   )r   r<   i)r   r;   )
Z
nose.toolsrg   r   rD   r   r   r?   Zcolumn_stackrd   r   )rg   r   r    r    r!   test_bs_errorsH  sh    *ro   )__all__Znumpyr   Z
patsy.utilr   r   r   Zpatsy.stater   rH   r"   r)   r1   objectr2   r   rb   Zslowrf   ro   r    r    r    r!   <module>   s   , .-