Skip to content

BUG: COMPAT:0.18 added scipy version check GH12887 #13007

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.18.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,7 @@ Other API changes
- Provide a proper ``__name__`` and ``__qualname__`` attributes for generic functions (:issue:`12021`)
- ``pd.concat(ignore_index=True)`` now uses ``RangeIndex`` as default (:issue:`12695`)
- ``pd.merge()`` and ``DataFrame.join()`` will show a ``UserWarning`` when merging/joining a single- with a multi-leveled dataframe (:issue:`9455`, :issue:`12219`)
- Compat with SciPy > 0.17 for deprecated ``piecewise_polynomial`` interpolation method (:issue:`12887`)

.. _whatsnew_0181.deprecations:

Expand Down
9 changes: 7 additions & 2 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -3452,8 +3452,8 @@ def replace(self, to_replace=None, value=None, inplace=False, limit=None,
----------
method : {'linear', 'time', 'index', 'values', 'nearest', 'zero',
'slinear', 'quadratic', 'cubic', 'barycentric', 'krogh',
'polynomial', 'spline' 'piecewise_polynomial', 'pchip',
'akima'}
'polynomial', 'spline', 'piecewise_polynomial',
'from_derivatives', 'pchip', 'akima'}

* 'linear': ignore the index and treat the values as equally
spaced. This is the only method supported on MultiIndexes.
Expand All @@ -3473,9 +3473,14 @@ def replace(self, to_replace=None, value=None, inplace=False, limit=None,
the scipy documentation for more on their behavior
`here <http://docs.scipy.org/doc/scipy/reference/interpolate.html#univariate-interpolation>`__ # noqa
`and here <http://docs.scipy.org/doc/scipy/reference/tutorial/interpolate.html>`__ # noqa
* 'from_derivatives' refers to BPoly.from_derivatives which
replaces 'piecewise_polynomial' interpolation method in scipy 0.18

.. versionadded:: 0.18.1
Added support for the 'akima' method
Added interpolate method 'from_derivatives' which replaces
'piecewise_polynomial' in scipy 0.18; backwards-compatible with
scipy < 0.18
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good


axis : {0, 1}, default 0
* 0: fill column-by-column
Expand Down
73 changes: 70 additions & 3 deletions pandas/core/missing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""

import numpy as np
from distutils.version import LooseVersion

import pandas.core.common as com
import pandas.algos as algos
Expand Down Expand Up @@ -85,13 +86,15 @@ def clean_interp_method(method, **kwargs):
order = kwargs.get('order')
valid = ['linear', 'time', 'index', 'values', 'nearest', 'zero', 'slinear',
'quadratic', 'cubic', 'barycentric', 'polynomial', 'krogh',
'piecewise_polynomial', 'pchip', 'akima', 'spline']
'piecewise_polynomial', 'pchip', 'akima', 'spline',
'from_derivatives']
if method in ('spline', 'polynomial') and order is None:
raise ValueError("You must specify the order of the spline or "
"polynomial.")
if method not in valid:
raise ValueError("method must be one of {0}."
"Got '{1}' instead.".format(valid, method))

return method


Expand Down Expand Up @@ -191,7 +194,8 @@ def _interp_limit(invalid, fw_limit, bw_limit):

sp_methods = ['nearest', 'zero', 'slinear', 'quadratic', 'cubic',
'barycentric', 'krogh', 'spline', 'polynomial',
'piecewise_polynomial', 'pchip', 'akima']
'from_derivatives', 'piecewise_polynomial', 'pchip', 'akima']

if method in sp_methods:
inds = np.asarray(xvalues)
# hack for DatetimeIndex, #1646
Expand All @@ -216,6 +220,7 @@ def _interpolate_scipy_wrapper(x, y, new_x, method, fill_value=None,
the list in _clean_interp_method
"""
try:
import scipy
from scipy import interpolate
# TODO: Why is DatetimeIndex being imported here?
from pandas import DatetimeIndex # noqa
Expand All @@ -228,7 +233,8 @@ def _interpolate_scipy_wrapper(x, y, new_x, method, fill_value=None,
alt_methods = {
'barycentric': interpolate.barycentric_interpolate,
'krogh': interpolate.krogh_interpolate,
'piecewise_polynomial': interpolate.piecewise_polynomial_interpolate,
'from_derivatives': _from_derivatives,
'piecewise_polynomial': _from_derivatives,
}

if getattr(x, 'is_all_dates', False):
Expand All @@ -248,6 +254,13 @@ def _interpolate_scipy_wrapper(x, y, new_x, method, fill_value=None,
except ImportError:
raise ImportError("Your version of Scipy does not support "
"Akima interpolation.")
elif method == 'piecewise_polynomial':
""" return the method for compat with scipy version """
if LooseVersion(scipy.__version__) <= LooseVersion('0.17'):
f = 'piecewise_polynomial_interpolate'
else:
f = 'from_derivatives'
alt_methods['piecewise_polynomial'] = getattr(interpolate, f)

interp1d_methods = ['nearest', 'zero', 'slinear', 'quadratic', 'cubic',
'polynomial']
Expand Down Expand Up @@ -277,6 +290,60 @@ def _interpolate_scipy_wrapper(x, y, new_x, method, fill_value=None,
return new_y


def _from_derivatives(xi, yi, x, order=None, der=0, extrapolate=False):
"""
Convenience function for interpolate.BPoly.from_derivatives

Construct a piecewise polynomial in the Bernstein basis, compatible
with the specified values and derivatives at breakpoints.

Parameters
----------
xi : array_like
sorted 1D array of x-coordinates
yi : array_like or list of array-likes
yi[i][j] is the j-th derivative known at xi[i]
orders : None or int or array_like of ints. Default: None.
Specifies the degree of local polynomials. If not None, some
derivatives are ignored.
der : int or list
How many derivatives to extract; None for all potentially nonzero
derivatives (that is a number equal to the number of points), or a
list of derivatives to extract. This numberincludes the function
value as 0th derivative.
extrapolate : bool, optional
Whether to extrapolate to ouf-of-bounds points based on first and last
intervals, or to return NaNs. Default: True.

See Also
--------
scipy.interpolate.BPoly.from_derivatives

Returns
-------
y : scalar or array_like
The result, of length R or length M or M by R,

"""
import scipy
from scipy import interpolate

if LooseVersion(scipy.__version__) < '0.18.0':
try:
method = interpolate.piecewise_polynomial_interpolate
return method(xi, yi.reshape(-1, 1), x,
orders=order, der=der)
except AttributeError:
pass

# return the method for compat with scipy version & backwards compat
method = interpolate.BPoly.from_derivatives
m = method(xi, yi.reshape(-1, 1),
orders=order, extrapolate=extrapolate)

return m(x)


def _akima_interpolate(xi, yi, x, der=0, axis=0):
"""
Convenience function for akima interpolation.
Expand Down
30 changes: 30 additions & 0 deletions pandas/tests/series/test_missing.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,36 @@ def test_interpolate_akima(self):
interp_s = ser.reindex(new_index).interpolate(method='akima')
assert_series_equal(interp_s[1:3], expected)

def test_interpolate_piecewise_polynomial(self):
tm._skip_if_no_scipy()

ser = Series([10, 11, 12, 13])

expected = Series([11.00, 11.25, 11.50, 11.75,
12.00, 12.25, 12.50, 12.75, 13.00],
index=Index([1.0, 1.25, 1.5, 1.75,
2.0, 2.25, 2.5, 2.75, 3.0]))
# interpolate at new_index
new_index = ser.index.union(Index([1.25, 1.5, 1.75, 2.25, 2.5, 2.75]))
interp_s = ser.reindex(new_index).interpolate(
method='piecewise_polynomial')
assert_series_equal(interp_s[1:3], expected)

def test_interpolate_from_derivatives(self):
tm._skip_if_no_scipy()

ser = Series([10, 11, 12, 13])

expected = Series([11.00, 11.25, 11.50, 11.75,
12.00, 12.25, 12.50, 12.75, 13.00],
index=Index([1.0, 1.25, 1.5, 1.75,
2.0, 2.25, 2.5, 2.75, 3.0]))
# interpolate at new_index
new_index = ser.index.union(Index([1.25, 1.5, 1.75, 2.25, 2.5, 2.75]))
interp_s = ser.reindex(new_index).interpolate(
method='from_derivatives')
assert_series_equal(interp_s[1:3], expected)

def test_interpolate_corners(self):
s = Series([np.nan, np.nan])
assert_series_equal(s.interpolate(), s)
Expand Down