Skip to content

API: fillna method argument should be None by default and raise on both ... #2284

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 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -3041,7 +3041,7 @@ def reorder_levels(self, order, axis=0):
#----------------------------------------------------------------------
# Filling NA's

def fillna(self, value=None, method='pad', axis=0, inplace=False,
def fillna(self, value=None, method=None, axis=0, inplace=False,
limit=None):
"""
Fill NA/NaN values using the specified method
Expand Down Expand Up @@ -3078,7 +3078,11 @@ def fillna(self, value=None, method='pad', axis=0, inplace=False,
self._consolidate_inplace()

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()
return self.T.fillna(method=method, limit=limit).T

new_blocks = []
Expand All @@ -3093,6 +3097,8 @@ def fillna(self, value=None, method='pad', axis=0, inplace=False,

new_data = BlockManager(new_blocks, self._data.axes)
else:
if method is not None:
raise ValueError('cannot specify both a fill method and value')
# Float type values
if len(self.columns) == 0:
return self
Expand All @@ -3117,6 +3123,14 @@ def fillna(self, value=None, method='pad', axis=0, inplace=False,
else:
return self._constructor(new_data)

def ffill(self, axis=0, inplace=False, limit=None):
return self.fillna(method='ffill', axis=axis, inplace=inplace,
limit=limit)

def bfill(self, axis=0, inplace=False, limit=None):
return self.fillna(method='bfill', axis=axis, inplace=inplace,
limit=limit)

def replace(self, to_replace, value=None, method='pad', axis=0,
inplace=False, limit=None):
"""
Expand Down
14 changes: 13 additions & 1 deletion pandas/core/panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -863,7 +863,7 @@ def _combine_panel(self, other, func):

return self._constructor(result_values, items, major, minor)

def fillna(self, value=None, method='pad'):
def fillna(self, value=None, method=None):
"""
Fill NaN values using the specified method.

Expand All @@ -889,15 +889,27 @@ def fillna(self, value=None, method='pad'):
DataFrame.reindex, DataFrame.asfreq
"""
if value is None:
if method is None:
raise ValueError('must specify a fill method or value')
result = {}
for col, s in self.iterkv():
result[col] = s.fillna(method=method, value=value)

return self._constructor.from_dict(result)
else:
if method is not None:
raise ValueError('cannot specify both a fill method and value')
new_data = self._data.fillna(value)
return self._constructor(new_data)


def ffill(self):
return self.fillna(method='ffill')

def bfill(self):
return self.fillna(method='bfill')


add = _panel_arith_method(operator.add, 'add')
subtract = sub = _panel_arith_method(operator.sub, 'subtract')
multiply = mul = _panel_arith_method(operator.mul, 'multiply')
Expand Down
12 changes: 10 additions & 2 deletions pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -2217,7 +2217,7 @@ def take(self, indices, axis=0):

truncate = generic.truncate

def fillna(self, value=None, method='pad', inplace=False,
def fillna(self, value=None, method=None, inplace=False,
limit=None):
"""
Fill NA/NaN values using the specified method
Expand Down Expand Up @@ -2249,12 +2249,14 @@ def fillna(self, value=None, method='pad', inplace=False,
return self.copy() if not inplace else self

if value is not None:
if method is not None:
raise ValueError('Cannot specify both a fill value and method')
result = self.copy() if not inplace else self
mask = isnull(self.values)
np.putmask(result, mask, value)
else:
if method is None: # pragma: no cover
raise ValueError('must specify a fill method')
raise ValueError('must specify a fill method or value')

fill_f = _get_fill_func(method)

Expand All @@ -2272,6 +2274,12 @@ def fillna(self, value=None, method='pad', inplace=False,

return result

def ffill(self, inplace=False, limit=None):
return self.fillna(method='ffill', inplace=inplace, limit=limit)

def bfill(self, inplace=False, limit=None):
return self.fillna(method='bfill', inplace=inplace, limit=limit)

def replace(self, to_replace, value=None, method='pad', inplace=False,
limit=None):
"""
Expand Down
2 changes: 1 addition & 1 deletion pandas/sparse/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,7 @@ def applymap(self, func):
return self.apply(lambda x: map(func, x))

@Appender(DataFrame.fillna.__doc__)
def fillna(self, value=None, method='pad', inplace=False, limit=None):
def fillna(self, value=None, method=None, inplace=False, limit=None):
new_series = {}
for k, v in self.iterkv():
new_series[k] = v.fillna(value=value, method=method, limit=limit)
Expand Down
2 changes: 1 addition & 1 deletion pandas/sparse/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ def sparse_reindex(self, new_index):
fill_value=self.fill_value)

@Appender(Series.fillna.__doc__)
def fillna(self, value=None, method='pad', inplace=False, limit=None):
def fillna(self, value=None, method=None, inplace=False, limit=None):
dense = self.to_dense()
filled = dense.fillna(value=value, method=method, limit=limit)
result = filled.to_sparse(kind=self.kind,
Expand Down
30 changes: 24 additions & 6 deletions pandas/tests/test_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -4567,6 +4567,23 @@ def test_fillna(self):

result = self.mixed_frame.fillna(value=0)

self.assertRaises(ValueError, self.tsframe.fillna)
self.assertRaises(ValueError, self.tsframe.fillna, 5, method='ffill')

def test_ffill(self):
self.tsframe['A'][:5] = nan
self.tsframe['A'][-5:] = nan

assert_frame_equal(self.tsframe.ffill(),
self.tsframe.fillna(method='ffill'))

def test_bfill(self):
self.tsframe['A'][:5] = nan
self.tsframe['A'][-5:] = nan

assert_frame_equal(self.tsframe.bfill(),
self.tsframe.fillna(method='bfill'))

def test_fillna_skip_certain_blocks(self):
# don't try to fill boolean, int blocks

Expand All @@ -4589,10 +4606,10 @@ def test_fillna_inplace(self):

df[1][:4] = np.nan
df[3][-4:] = np.nan
expected = df.fillna()
expected = df.fillna(method='ffill')
self.assert_(expected is not df)

df2 = df.fillna(inplace=True)
df2 = df.fillna(method='ffill', inplace=True)
self.assert_(df2 is df)
assert_frame_equal(df2, expected)

Expand Down Expand Up @@ -4623,13 +4640,13 @@ def test_fillna_columns(self):
df = DataFrame(np.random.randn(10, 10))
df.values[:, ::2] = np.nan

result = df.fillna(axis=1)
result = df.fillna(method='ffill', axis=1)
expected = df.T.fillna(method='pad').T
assert_frame_equal(result, expected)

df.insert(6, 'foo', 5)
result = df.fillna(axis=1)
expected = df.astype(float).fillna(axis=1)
result = df.fillna(method='ffill', axis=1)
expected = df.astype(float).fillna(method='ffill', axis=1)
assert_frame_equal(result, expected)

def test_fillna_invalid_method(self):
Expand Down Expand Up @@ -7317,7 +7334,8 @@ def test_fillna_col_reordering(self):
cols = ["COL." + str(i) for i in range(5, 0, -1)]
data = np.random.rand(20, 5)
df = DataFrame(index=range(20), columns=cols, data=data)
self.assert_(df.columns.tolist() == df.fillna().columns.tolist())
filled = df.fillna(method='ffill')
self.assert_(df.columns.tolist() == filled.columns.tolist())

def test_take(self):
# homogeneous
Expand Down
9 changes: 9 additions & 0 deletions pandas/tests/test_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,15 @@ def test_fillna(self):
filled = empty.fillna(0)
assert_panel_equal(filled, empty)

self.assertRaises(ValueError, self.panel.fillna)
self.assertRaises(ValueError, self.panel.fillna, 5, method='ffill')

def test_ffill_bfill(self):
assert_panel_equal(self.panel.ffill(),
self.panel.fillna(method='ffill'))
assert_panel_equal(self.panel.bfill(),
self.panel.fillna(method='bfill'))

def test_truncate_fillna_bug(self):
# #1823
result = self.panel.truncate(before=None, after=None, axis='items')
Expand Down
21 changes: 17 additions & 4 deletions pandas/tests/test_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -2818,25 +2818,28 @@ def test_isin(self):

def test_fillna_int(self):
s = Series(np.random.randint(-100, 100, 50))
self.assert_(s.fillna(inplace=True) is s)
assert_series_equal(s.fillna(inplace=False), s)
self.assert_(s.fillna(method='ffill', inplace=True) is s)
assert_series_equal(s.fillna(method='ffill', inplace=False), s)

#-------------------------------------------------------------------------------
# TimeSeries-specific

def test_fillna(self):
ts = Series([0., 1., 2., 3., 4.], index=tm.makeDateIndex(5))

self.assert_(np.array_equal(ts, ts.fillna()))
self.assert_(np.array_equal(ts, ts.fillna(method='ffill')))

ts[2] = np.NaN

self.assert_(np.array_equal(ts.fillna(), [0., 1., 1., 3., 4.]))
self.assert_(np.array_equal(ts.fillna(method='ffill'), [0., 1., 1., 3., 4.]))
self.assert_(np.array_equal(ts.fillna(method='backfill'),
[0., 1., 3., 3., 4.]))

self.assert_(np.array_equal(ts.fillna(value=5), [0., 1., 5., 3., 4.]))

self.assertRaises(ValueError, ts.fillna)
self.assertRaises(ValueError, self.ts.fillna, value=0, method='ffill')

def test_fillna_bug(self):
x = Series([nan, 1., nan, 3., nan],['z','a','b','c','d'])
filled = x.fillna(method='ffill')
Expand All @@ -2863,6 +2866,16 @@ def test_fillna_invalid_method(self):
except ValueError, inst:
self.assert_('ffil' in str(inst))

def test_ffill(self):
ts = Series([0., 1., 2., 3., 4.], index=tm.makeDateIndex(5))
ts[2] = np.NaN
assert_series_equal(ts.ffill(), ts.fillna(method='ffill'))

def test_bfill(self):
ts = Series([0., 1., 2., 3., 4.], index=tm.makeDateIndex(5))
ts[2] = np.NaN
assert_series_equal(ts.bfill(), ts.fillna(method='bfill'))

def test_replace(self):
N = 100
ser = Series(np.random.randn(N))
Expand Down