diff --git a/doc/source/whatsnew/v0.20.0.txt b/doc/source/whatsnew/v0.20.0.txt index e7b2fc5a6505d..dd44b97c9cddf 100644 --- a/doc/source/whatsnew/v0.20.0.txt +++ b/doc/source/whatsnew/v0.20.0.txt @@ -300,3 +300,4 @@ Bug Fixes - Bug in ``Series.unique()`` in which unsigned 64-bit integers were causing overflow (:issue:`14721`) - Require at least 0.23 version of cython to avoid problems with character encodings (:issue:`14699`) - Bug in converting object elements of array-like objects to unsigned 64-bit integers (:issue:`4471`) +- Bug in ``pd.Panel.ffill`` where ``axis`` was not propagated (:issue:`14499`) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 3678168890444..f1c4a2e87bb70 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -3262,10 +3262,14 @@ def fillna(self, value=None, method=None, axis=None, inplace=False, 'you passed a "{0}"'.format(type(value).__name__)) self._consolidate_inplace() - # set the default here, so functions examining the signaure + # set the default here, so functions examining the signature # can detect if something was set (e.g. in groupby) (GH9221) if axis is None: - axis = 0 + if self.ndim == 3: + axis = 1 + else: + axis = 0 + axis = self._get_axis_number(axis) method = missing.clean_fill_method(method) @@ -3273,15 +3277,6 @@ def fillna(self, value=None, method=None, axis=None, inplace=False, if value is None: if method is None: raise ValueError('must specify a fill method or value') - if self._is_mixed_type and axis == 1: - if inplace: - raise NotImplementedError() - result = self.T.fillna(method=method, limit=limit).T - - # need to downcast here because of all of the transposes - result._data = result._data.downcast() - - return result # > 3d if self.ndim > 3: @@ -3290,21 +3285,41 @@ def fillna(self, value=None, method=None, axis=None, inplace=False, # 3d elif self.ndim == 3: - # fill in 2d chunks - result = dict([(col, s.fillna(method=method, value=value)) - for col, s in self.iteritems()]) + if axis == 0: + frame = self.swapaxes(0, 1) + axis2d = 0 + else: + frame = self + axis2d = axis - 1 + result = dict([(col, s.fillna(method=method, + value=value, + axis=axis2d)) + for col, s in frame.iteritems()]) new_obj = self._constructor.\ from_dict(result).__finalize__(self) + if axis == 0: + new_obj = new_obj.swapaxes(0, 1) new_data = new_obj._data else: # 2d or less - method = missing.clean_fill_method(method) - new_data = self._data.interpolate(method=method, axis=axis, - limit=limit, inplace=inplace, - coerce=True, - downcast=downcast) + if self._is_mixed_type and axis == 1: + if inplace: + raise NotImplementedError() + result = self.T.fillna(method=method, limit=limit).T + + # need to downcast here because of all of the transposes + result._data = result._data.downcast() + + return result + else: + method = missing.clean_fill_method(method) + new_data = self._data.interpolate(method=method, axis=axis, + limit=limit, + inplace=inplace, + coerce=True, + downcast=downcast) else: if method is not None: raise ValueError('cannot specify both a fill method and value') diff --git a/pandas/tests/test_panel.py b/pandas/tests/test_panel.py index 9cb2dd5a40ac4..43c7ec663fde0 100644 --- a/pandas/tests/test_panel.py +++ b/pandas/tests/test_panel.py @@ -1519,6 +1519,50 @@ def test_ffill_bfill(self): assert_panel_equal(self.panel.bfill(), self.panel.fillna(method='bfill')) + def test_ffill_bfill_axis(self): + # GH 14499 + a = Panel({ + 'a': np.arange(15, dtype=float).reshape((5, 3)), + 'b': np.arange(15, 30, dtype=float).reshape((5, 3)) + }) + f0 = a.copy() + f1 = a.copy() + f2 = a.copy() + b0 = a.copy() + b1 = a.copy() + b2 = a.copy() + a['a'].loc[1, 1] = np.nan + f0['a'].loc[1, 1] = np.nan + f1['a'].loc[1, 1] = 1 + f2['a'].loc[1, 1] = 3 + b0['a'].loc[1, 1] = 19.0 + b1['a'].loc[1, 1] = 7 + b2['a'].loc[1, 1] = 5 + + # method='ffill' + # axis=0 + assert_panel_equal(a.ffill(axis=0), f0) + + # method='ffill' + # axis=1 + assert_panel_equal(a.ffill(axis=1), f1) + + # method='ffill' + # axis=2 + assert_panel_equal(a.ffill(axis=2), f2) + + # method='bfill' + # axis=1 + assert_panel_equal(a.bfill(axis=0), b0) + + # method='bfill' + # axis=1 + assert_panel_equal(a.bfill(axis=1), b1) + + # method='bfill' + # axis=2 + assert_panel_equal(a.bfill(axis=2), b2) + def test_truncate_fillna_bug(self): # #1823 result = self.panel.truncate(before=None, after=None, axis='items')