Skip to content

Commit 326ef95

Browse files
committed
Merge pull request #7440 from toddrjen/nannone
support axis=None for nanmedian ( issue #7352 )
2 parents 887fe22 + 562b86e commit 326ef95

File tree

3 files changed

+54
-27
lines changed

3 files changed

+54
-27
lines changed

doc/source/v0.14.1.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ Bug Fixes
217217
(:issue:`7353`)
218218
- Bug in several ``nanops`` functions when ``axis==0`` for
219219
1-dimensional ``nan`` arrays (:issue:`7354`)
220+
- Bug where ``nanops.nanmedian`` doesn't work when ``axis==None``
221+
(:issue:`7352`)
220222

221223

222224

pandas/core/nanops.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,9 @@ def get_median(x):
286286
if values.dtype != np.float64:
287287
values = values.astype('f8')
288288

289+
if axis is None:
290+
values = values.ravel()
291+
289292
notempty = values.size
290293

291294
# an array from a frame

pandas/tests/test_nanops.py

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
class TestnanopsDataFrame(tm.TestCase):
1515
def setUp(self):
16+
np.random.seed(11235)
17+
1618
self.arr_shape = (11, 7, 5)
1719

1820
self.arr_float = np.random.randn(*self.arr_shape)
@@ -118,11 +120,38 @@ def check_results(self, targ, res, axis):
118120
res = getattr(res, 'values', res)
119121
if axis != 0 and hasattr(targ, 'shape') and targ.ndim:
120122
res = np.split(res, [targ.shape[0]], axis=0)[0]
121-
tm.assert_almost_equal(targ, res)
123+
try:
124+
tm.assert_almost_equal(targ, res)
125+
except:
126+
# There are sometimes rounding errors with
127+
# complex and object dtypes.
128+
# If it isn't one of those, re-raise the error.
129+
if not hasattr(res, 'dtype') or res.dtype.kind not in ['c', 'O']:
130+
raise
131+
# convert object dtypes to something that can be split into
132+
# real and imaginary parts
133+
if res.dtype.kind == 'O':
134+
if targ.dtype.kind != 'O':
135+
res = res.astype(targ.dtype)
136+
else:
137+
try:
138+
res = res.astype('c16')
139+
except:
140+
res = res.astype('f8')
141+
try:
142+
targ = targ.astype('c16')
143+
except:
144+
targ = targ.astype('f8')
145+
# there should never be a case where numpy returns an object
146+
# but nanops doesn't, so make that an exception
147+
elif targ.dtype.kind == 'O':
148+
raise
149+
tm.assert_almost_equal(targ.real, res.real)
150+
tm.assert_almost_equal(targ.imag, res.imag)
122151

123152
def check_fun_data(self, testfunc, targfunc,
124153
testarval, targarval, targarnanval, **kwargs):
125-
for axis in list(range(targarval.ndim)):
154+
for axis in list(range(targarval.ndim))+[None]:
126155
for skipna in [False, True]:
127156
targartempval = targarval if skipna else targarnanval
128157
try:
@@ -215,6 +244,12 @@ def check_funs(self, testfunc, targfunc,
215244

216245
if allow_obj:
217246
self.arr_obj = np.vstack(objs)
247+
# some nanops handle object dtypes better than their numpy
248+
# counterparts, so the numpy functions need to be given something
249+
# else
250+
if allow_obj == 'convert':
251+
targfunc = partial(self._badobj_wrap,
252+
func=targfunc, allow_complex=allow_complex)
218253
self.check_fun(testfunc, targfunc, 'arr_obj', **kwargs)
219254

220255
def check_funs_ddof(self, testfunc, targfunc,
@@ -229,6 +264,14 @@ def check_funs_ddof(self, testfunc, targfunc,
229264
except BaseException as exc:
230265
exc.args += ('ddof %s' % ddof,)
231266

267+
def _badobj_wrap(self, value, func, allow_complex=True, **kwargs):
268+
if value.dtype.kind == 'O':
269+
if allow_complex:
270+
value = value.astype('c16')
271+
else:
272+
value = value.astype('f8')
273+
return func(value, **kwargs)
274+
232275
def test_nanany(self):
233276
self.check_funs(nanops.nanany, np.any,
234277
allow_all_nan=False, allow_str=False, allow_date=False)
@@ -241,36 +284,15 @@ def test_nansum(self):
241284
self.check_funs(nanops.nansum, np.sum,
242285
allow_str=False, allow_date=False)
243286

244-
def _nanmean_wrap(self, value, *args, **kwargs):
245-
dtype = value.dtype
246-
res = nanops.nanmean(value, *args, **kwargs)
247-
if dtype.kind == 'O':
248-
res = np.round(res, decimals=13)
249-
return res
250-
251-
def _mean_wrap(self, value, *args, **kwargs):
252-
dtype = value.dtype
253-
if dtype.kind == 'O':
254-
value = value.astype('c16')
255-
res = np.mean(value, *args, **kwargs)
256-
if dtype.kind == 'O':
257-
res = np.round(res, decimals=13)
258-
return res
259-
260287
def test_nanmean(self):
261-
self.check_funs(self._nanmean_wrap, self._mean_wrap,
288+
self.check_funs(nanops.nanmean, np.mean,
262289
allow_complex=False, allow_obj=False,
263290
allow_str=False, allow_date=False)
264291

265-
def _median_wrap(self, value, *args, **kwargs):
266-
if value.dtype.kind == 'O':
267-
value = value.astype('c16')
268-
res = np.median(value, *args, **kwargs)
269-
return res
270-
271292
def test_nanmedian(self):
272-
self.check_funs(nanops.nanmedian, self._median_wrap,
273-
allow_complex=False, allow_str=False, allow_date=False)
293+
self.check_funs(nanops.nanmedian, np.median,
294+
allow_complex=False, allow_str=False, allow_date=False,
295+
allow_obj='convert')
274296

275297
def test_nanvar(self):
276298
self.check_funs_ddof(nanops.nanvar, np.var,

0 commit comments

Comments
 (0)