diff --git a/doc/source/v0.14.1.txt b/doc/source/v0.14.1.txt index 92e19ba43ccb7..aacc4ae989611 100644 --- a/doc/source/v0.14.1.txt +++ b/doc/source/v0.14.1.txt @@ -217,6 +217,8 @@ Bug Fixes (:issue:`7353`) - Bug in several ``nanops`` functions when ``axis==0`` for 1-dimensional ``nan`` arrays (:issue:`7354`) +- Bug where ``nanops.nanmedian`` doesn't work when ``axis==None`` + (:issue:`7352`) diff --git a/pandas/core/nanops.py b/pandas/core/nanops.py index 3be194f9673f3..4b78164003eed 100644 --- a/pandas/core/nanops.py +++ b/pandas/core/nanops.py @@ -286,6 +286,9 @@ def get_median(x): if values.dtype != np.float64: values = values.astype('f8') + if axis is None: + values = values.ravel() + notempty = values.size # an array from a frame diff --git a/pandas/tests/test_nanops.py b/pandas/tests/test_nanops.py index 47ca288177946..118ccf0141225 100644 --- a/pandas/tests/test_nanops.py +++ b/pandas/tests/test_nanops.py @@ -13,6 +13,8 @@ class TestnanopsDataFrame(tm.TestCase): def setUp(self): + np.random.seed(11235) + self.arr_shape = (11, 7, 5) self.arr_float = np.random.randn(*self.arr_shape) @@ -118,11 +120,38 @@ def check_results(self, targ, res, axis): res = getattr(res, 'values', res) if axis != 0 and hasattr(targ, 'shape') and targ.ndim: res = np.split(res, [targ.shape[0]], axis=0)[0] - tm.assert_almost_equal(targ, res) + try: + tm.assert_almost_equal(targ, res) + except: + # There are sometimes rounding errors with + # complex and object dtypes. + # If it isn't one of those, re-raise the error. + if not hasattr(res, 'dtype') or res.dtype.kind not in ['c', 'O']: + raise + # convert object dtypes to something that can be split into + # real and imaginary parts + if res.dtype.kind == 'O': + if targ.dtype.kind != 'O': + res = res.astype(targ.dtype) + else: + try: + res = res.astype('c16') + except: + res = res.astype('f8') + try: + targ = targ.astype('c16') + except: + targ = targ.astype('f8') + # there should never be a case where numpy returns an object + # but nanops doesn't, so make that an exception + elif targ.dtype.kind == 'O': + raise + tm.assert_almost_equal(targ.real, res.real) + tm.assert_almost_equal(targ.imag, res.imag) def check_fun_data(self, testfunc, targfunc, testarval, targarval, targarnanval, **kwargs): - for axis in list(range(targarval.ndim)): + for axis in list(range(targarval.ndim))+[None]: for skipna in [False, True]: targartempval = targarval if skipna else targarnanval try: @@ -215,6 +244,12 @@ def check_funs(self, testfunc, targfunc, if allow_obj: self.arr_obj = np.vstack(objs) + # some nanops handle object dtypes better than their numpy + # counterparts, so the numpy functions need to be given something + # else + if allow_obj == 'convert': + targfunc = partial(self._badobj_wrap, + func=targfunc, allow_complex=allow_complex) self.check_fun(testfunc, targfunc, 'arr_obj', **kwargs) def check_funs_ddof(self, testfunc, targfunc, @@ -229,6 +264,14 @@ def check_funs_ddof(self, testfunc, targfunc, except BaseException as exc: exc.args += ('ddof %s' % ddof,) + def _badobj_wrap(self, value, func, allow_complex=True, **kwargs): + if value.dtype.kind == 'O': + if allow_complex: + value = value.astype('c16') + else: + value = value.astype('f8') + return func(value, **kwargs) + def test_nanany(self): self.check_funs(nanops.nanany, np.any, allow_all_nan=False, allow_str=False, allow_date=False) @@ -241,36 +284,15 @@ def test_nansum(self): self.check_funs(nanops.nansum, np.sum, allow_str=False, allow_date=False) - def _nanmean_wrap(self, value, *args, **kwargs): - dtype = value.dtype - res = nanops.nanmean(value, *args, **kwargs) - if dtype.kind == 'O': - res = np.round(res, decimals=13) - return res - - def _mean_wrap(self, value, *args, **kwargs): - dtype = value.dtype - if dtype.kind == 'O': - value = value.astype('c16') - res = np.mean(value, *args, **kwargs) - if dtype.kind == 'O': - res = np.round(res, decimals=13) - return res - def test_nanmean(self): - self.check_funs(self._nanmean_wrap, self._mean_wrap, + self.check_funs(nanops.nanmean, np.mean, allow_complex=False, allow_obj=False, allow_str=False, allow_date=False) - def _median_wrap(self, value, *args, **kwargs): - if value.dtype.kind == 'O': - value = value.astype('c16') - res = np.median(value, *args, **kwargs) - return res - def test_nanmedian(self): - self.check_funs(nanops.nanmedian, self._median_wrap, - allow_complex=False, allow_str=False, allow_date=False) + self.check_funs(nanops.nanmedian, np.median, + allow_complex=False, allow_str=False, allow_date=False, + allow_obj='convert') def test_nanvar(self): self.check_funs_ddof(nanops.nanvar, np.var,