From 6920f2af88ace4948eca2676c6ad314f6e28e83d Mon Sep 17 00:00:00 2001 From: Debian Science Maintainers Date: Sun, 29 Aug 2021 20:09:28 +0100 Subject: [PATCH] Be compatible with scipy 1.7 Bug-Debian: https://bugs.debian.org/992691 Origin: upstream 42e377f87a7817f918a4e790b83fbe16064b4268 + part of edd4296765d96b011532456bdf861c2e0ca8bc38 + 4f32f3990fbba0ee440af47e23a9354fdb7a0285 Author: Kevin "bashtage" Sheppard Forwarded: not-needed Gbp-Pq: Name scipy17_compat.patch --- statsmodels/compat/scipy.py | 34 ------------------- statsmodels/distributions/discrete.py | 2 +- .../genmod/_tweedie_compound_poisson.py | 10 +++--- statsmodels/regression/tests/test_rolling.py | 6 ++-- statsmodels/stats/descriptivestats.py | 8 ++++- statsmodels/stats/stattools.py | 4 ++- .../tests/test_dist_dependant_measures.py | 15 ++++---- .../tsa/arima/tests/test_specification.py | 4 +-- statsmodels/tsa/arima/tools.py | 6 +++- statsmodels/tsa/vector_ar/tests/test_svar.py | 4 +-- 10 files changed, 38 insertions(+), 55 deletions(-) diff --git a/statsmodels/compat/scipy.py b/statsmodels/compat/scipy.py index 0ca2ef3..9bd9b0f 100644 --- a/statsmodels/compat/scipy.py +++ b/statsmodels/compat/scipy.py @@ -66,37 +66,3 @@ def _valarray(shape, value=np.nan, typecode=None): if not isinstance(out, np.ndarray): out = np.asarray(out) return out - - -def _lazywhere(cond, arrays, f, fillvalue=None, f2=None): - """ - np.where(cond, x, fillvalue) always evaluates x even where cond is False. - This one only evaluates f(arr1[cond], arr2[cond], ...). - For example, - >>> a, b = np.array([1, 2, 3, 4]), np.array([5, 6, 7, 8]) - >>> def f(a, b): - return a*b - >>> _lazywhere(a > 2, (a, b), f, np.nan) - array([ nan, nan, 21., 32.]) - Notice it assumes that all `arrays` are of the same shape, or can be - broadcasted together. - """ - if fillvalue is None: - if f2 is None: - raise ValueError("One of (fillvalue, f2) must be given.") - else: - fillvalue = np.nan - else: - if f2 is not None: - raise ValueError("Only one of (fillvalue, f2) can be given.") - - arrays = np.broadcast_arrays(*arrays) - temp = tuple(np.extract(cond, arr) for arr in arrays) - tcode = np.mintypecode([a.dtype.char for a in arrays]) - out = _valarray(np.shape(arrays[0]), value=fillvalue, typecode=tcode) - np.place(out, cond, f(*temp)) - if f2 is not None: - temp = tuple(np.extract(~cond, arr) for arr in arrays) - np.place(out, ~cond, f2(*temp)) - - return out diff --git a/statsmodels/distributions/discrete.py b/statsmodels/distributions/discrete.py index 178926e..16073f0 100644 --- a/statsmodels/distributions/discrete.py +++ b/statsmodels/distributions/discrete.py @@ -1,7 +1,7 @@ import numpy as np from scipy.stats import rv_discrete, nbinom, poisson from scipy.special import gammaln -from statsmodels.compat.scipy import _lazywhere +from scipy._lib._util import _lazywhere class genpoisson_p_gen(rv_discrete): diff --git a/statsmodels/genmod/_tweedie_compound_poisson.py b/statsmodels/genmod/_tweedie_compound_poisson.py index 5a0c0c0..1b393c0 100644 --- a/statsmodels/genmod/_tweedie_compound_poisson.py +++ b/statsmodels/genmod/_tweedie_compound_poisson.py @@ -17,7 +17,7 @@ Smyth G.K. and Jørgensen B. 2002. Fitting Tweedie's compound Poisson model to insurance claims data: dispersion modelling. ASTIN Bulletin 32: 143–157 """ import numpy as np -from scipy._lib._util import _lazywhere as lazywhere +from scipy._lib._util import _lazywhere from scipy.special import gammaln @@ -76,10 +76,10 @@ def density_otherwise(y, mu, p, phi): def series_density(y, mu, p, phi): - density = lazywhere(np.array(y) > 0, - (y, mu, p, phi), - f=density_otherwise, - f2=density_at_zero) + density = _lazywhere(np.array(y) > 0, + (y, mu, p, phi), + f=density_otherwise, + f2=density_at_zero) return density diff --git a/statsmodels/regression/tests/test_rolling.py b/statsmodels/regression/tests/test_rolling.py index f1d1dea..7397432 100644 --- a/statsmodels/regression/tests/test_rolling.py +++ b/statsmodels/regression/tests/test_rolling.py @@ -1,5 +1,6 @@ from io import BytesIO from itertools import product +import warnings import numpy as np import pandas as pd @@ -261,8 +262,9 @@ def test_plot(): res.plot_recursive_coefficient(variables="x4") fig = plt.Figure() - with pytest.warns(Warning): - # Just silence the warning + # Just silence the warning + with warnings.catch_warnings(): + warnings.simplefilter("ignore") out = res.plot_recursive_coefficient(fig=fig) assert out is fig res.plot_recursive_coefficient(alpha=None, figsize=(30, 7)) diff --git a/statsmodels/stats/descriptivestats.py b/statsmodels/stats/descriptivestats.py index 96d455c..d5ad2f2 100644 --- a/statsmodels/stats/descriptivestats.py +++ b/statsmodels/stats/descriptivestats.py @@ -446,8 +446,14 @@ class Description: else: iqr = mean + def _safe_jarque_bera(c): + a = np.asarray(c) + if a.shape[0] < 2: + return (np.nan,) * 4 + return jarque_bera(a) + jb = df.apply( - lambda x: list(jarque_bera(x.dropna())), result_type="expand" + lambda x: list(_safe_jarque_bera(x.dropna())), result_type="expand" ).T nan_mean = mean.copy() nan_mean.loc[nan_mean == 0] = np.nan diff --git a/statsmodels/stats/stattools.py b/statsmodels/stats/stattools.py index d349c47..2ee1a6e 100644 --- a/statsmodels/stats/stattools.py +++ b/statsmodels/stats/stattools.py @@ -118,7 +118,9 @@ def jarque_bera(resids, axis=0): where n is the number of data points, S is the sample skewness, and K is the sample kurtosis of the data. """ - resids = np.asarray(resids) + resids = np.atleast_1d(np.asarray(resids, dtype=float)) + if resids.size < 2: + raise ValueError("resids must contain at least 2 elements") # Calculate residual skewness and kurtosis skew = stats.skew(resids, axis=axis) kurtosis = 3 + stats.kurtosis(resids, axis=axis) diff --git a/statsmodels/stats/tests/test_dist_dependant_measures.py b/statsmodels/stats/tests/test_dist_dependant_measures.py index af373a6..2b16441 100644 --- a/statsmodels/stats/tests/test_dist_dependant_measures.py +++ b/statsmodels/stats/tests/test_dist_dependant_measures.py @@ -95,7 +95,10 @@ class TestDistDependenceMeasures(object): assert_almost_equal(pval, self.pval_asym_exp, 3) def test_statistics_for_2d_input(self): - stats = ddm.distance_statistics(self.x, self.y) + stats = ddm.distance_statistics( + np.asarray(self.x, dtype=float), + np.asarray(self.y, dtype=float) + ) assert_almost_equal(stats.test_statistic, self.test_stat_emp_exp, 0) assert_almost_equal(stats.distance_correlation, self.dcor_exp, 4) @@ -105,7 +108,7 @@ class TestDistDependenceMeasures(object): assert_almost_equal(stats.S, self.S_exp, 4) def test_statistics_for_1d_input(self): - x = np.array(range(1, 21)) + x = np.array(range(1, 21), dtype=float) y = x + np.log(x) stats = ddm.distance_statistics(x, y) @@ -141,8 +144,8 @@ class TestDistDependenceMeasures(object): except IGNORED_EXCEPTIONS: pytest.skip('Failed with HTTPError or URLError, these are random') - x = iris[:50] - y = iris[50:100] + x = np.asarray(iris[:50], dtype=float) + y = np.asarray(iris[50:100], dtype=float) stats = ddm.distance_statistics(x, y) @@ -181,8 +184,8 @@ class TestDistDependenceMeasures(object): except IGNORED_EXCEPTIONS: pytest.skip('Failed with HTTPError or URLError, these are random') - x = quakes[:50] - y = quakes[50:100] + x = np.asarray(quakes[:50], dtype=float) + y = np.asarray(quakes[50:100], dtype=float) stats = ddm.distance_statistics(x, y) diff --git a/statsmodels/tsa/arima/tests/test_specification.py b/statsmodels/tsa/arima/tests/test_specification.py index 91cc61c..8f8164e 100644 --- a/statsmodels/tsa/arima/tests/test_specification.py +++ b/statsmodels/tsa/arima/tests/test_specification.py @@ -217,7 +217,7 @@ def check_methods(spec, order, seasonal_order, enforce_stationarity, (1, 0, 0, 0, np.array([0.5, 1.]), 'p'), (1, 0, 0, 0, np.array([-0.2, 100.]), 'p'), (2, 0, 0, 0, np.array([-0.2, 0.5, 100.]), 'p'), - (20, 0, 0, 0, np.array([0] * 20 + [100.]), 'p'), + (20, 0, 0, 0, np.array([0.0] * 20 + [100.]), 'p'), # ARI models (0, 1, 0, 0, np.array([1.]), 'p'), (0, 1, 1, 4, np.array([1.]), 'p'), @@ -228,7 +228,7 @@ def check_methods(spec, order, seasonal_order, enforce_stationarity, (1, 0, 0, 0, np.array([0.5, 1.]), 'q'), (1, 0, 0, 0, np.array([-0.2, 100.]), 'q'), (2, 0, 0, 0, np.array([-0.2, 0.5, 100.]), 'q'), - (20, 0, 0, 0, np.array([0] * 20 + [100.]), 'q'), + (20, 0, 0, 0, np.array([0.0] * 20 + [100.]), 'q'), # IMA models (0, 1, 0, 0, np.array([1.]), 'q'), (0, 1, 1, 4, np.array([1.]), 'q'), diff --git a/statsmodels/tsa/arima/tools.py b/statsmodels/tsa/arima/tools.py index c9ed7f3..40dd2ae 100644 --- a/statsmodels/tsa/arima/tools.py +++ b/statsmodels/tsa/arima/tools.py @@ -139,7 +139,11 @@ def validate_basic(params, length, allow_infnan=False, title=None): # Check for invalid type and coerce to non-integer try: - params = np.array(params) * 1.0 + params = np.array(params, dtype=object) + complex_types = (complex, np.complex) + is_complex = [isinstance(p, complex_types) for p in params.ravel()] + dtype = complex if any(is_complex) else float + params = np.array(params, dtype=dtype) except TypeError: raise ValueError('Parameters vector%s includes invalid values.' % title) diff --git a/statsmodels/tsa/vector_ar/tests/test_svar.py b/statsmodels/tsa/vector_ar/tests/test_svar.py index 7f5411c..d80ba01 100644 --- a/statsmodels/tsa/vector_ar/tests/test_svar.py +++ b/statsmodels/tsa/vector_ar/tests/test_svar.py @@ -22,8 +22,8 @@ class TestSVAR(object): mdata = mdata[['realgdp', 'realcons', 'realinv']] data = mdata.values data = np.diff(np.log(data), axis=0) - A = np.asarray([[1, 0, 0], ['E', 1, 0], ['E', 'E', 1]]) - B = np.asarray([['E', 0, 0], [0, 'E', 0], [0, 0, 'E']]) + A = np.asarray([[1, 0, 0], ['E', 1, 0], ['E', 'E', 1]], dtype="U") + B = np.asarray([['E', 0, 0], [0, 'E', 0], [0, 0, 'E']], dtype="U") results = SVAR(data, svar_type='AB', A=A, B=B).fit(maxlags=3) cls.res1 = results #cls.res2 = results_svar.SVARdataResults() -- 2.30.2