Skip to content

Commit

Permalink
Merge pull request pandas-dev#6628 from jreback/fillna_limit
Browse files Browse the repository at this point in the history
BUG: Bug in fillna with limit and value specified
  • Loading branch information
jreback committed Mar 13, 2014
2 parents 98f51f5 + 74fbfcb commit e19b2eb
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 7 deletions.
2 changes: 1 addition & 1 deletion doc/source/release.rst
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ Bug Fixes
- Bug in sql writing with mixed dtypes possibly leading to data loss (:issue:`6509`)
- Bug in popping from a Series (:issue:`6600`)
- Bug in ``iloc`` indexing when positional indexer matched Int64Index of corresponding axis no reordering happened (:issue:`6612`)

- Bug in ``fillna`` with ``limit`` and ``value`` specified

pandas 0.13.1
-------------
Expand Down
10 changes: 7 additions & 3 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2162,7 +2162,9 @@ def fillna(self, value=None, method=None, axis=0, inplace=False,
from pandas import Series
value = Series(value)

new_data = self._data.fillna(value=value, inplace=inplace,
new_data = self._data.fillna(value=value,
limit=limit,
inplace=inplace,
downcast=downcast)

elif isinstance(value, (dict, com.ABCSeries)):
Expand All @@ -2176,10 +2178,12 @@ def fillna(self, value=None, method=None, axis=0, inplace=False,
if k not in result:
continue
obj = result[k]
obj.fillna(v, inplace=True)
obj.fillna(v, limit=limit, inplace=True)
return result
else:
new_data = self._data.fillna(value=value, inplace=inplace,
new_data = self._data.fillna(value=value,
limit=limit,
inplace=inplace,
downcast=downcast)

if inplace:
Expand Down
20 changes: 17 additions & 3 deletions pandas/core/internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,14 +367,19 @@ def apply(self, func, **kwargs):
""" apply the function to my values; return a block if we are not one """
return self.as_block(func(self.values))

def fillna(self, value, inplace=False, downcast=None):
def fillna(self, value, limit=None, inplace=False, downcast=None):
if not self._can_hold_na:
if inplace:
return [self]
else:
return [self.copy()]

mask = com.isnull(self.values)
if limit is not None:
if self.ndim > 2:
raise NotImplementedError
mask[mask.cumsum(self.ndim-1)>limit]=False

value = self._try_fill(value)
blocks = self.putmask(mask, value, inplace=inplace)
return self._maybe_downcast(blocks, downcast)
Expand Down Expand Up @@ -1680,11 +1685,18 @@ def _try_fill(self, value):
value = tslib.iNaT
return value

def fillna(self, value, inplace=False, downcast=None):
def fillna(self, value, limit=None,
inplace=False, downcast=None):

# straight putmask here
values = self.values if inplace else self.values.copy()
mask = com.isnull(self.values)
value = self._try_fill(value)
if limit is not None:
if self.ndim > 2:
raise NotImplementedError
mask[mask.cumsum(self.ndim-1)>limit]=False

np.putmask(values, mask, value)
return [self if inplace else
make_block(values, self.items, self.ref_items, fastpath=True)]
Expand Down Expand Up @@ -1889,8 +1901,10 @@ def interpolate(self, method='pad', axis=0, inplace=False,
self.values.to_dense(), method, axis, limit, fill_value)
return self.make_block(values, self.items, self.ref_items)

def fillna(self, value, inplace=False, downcast=None):
def fillna(self, value, limit=None, inplace=False, downcast=None):
# we may need to upcast our fill to match our dtype
if limit is not None:
raise NotImplementedError
if issubclass(self.dtype.type, np.floating):
value = float(value)
values = self.values if inplace else self.values.copy()
Expand Down
11 changes: 11 additions & 0 deletions pandas/tests/test_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -7113,6 +7113,17 @@ def test_fillna(self):
df.fillna({ 2: 'foo' }, inplace=True)
assert_frame_equal(df, expected)

# limit and value
df = DataFrame(np.random.randn(10,3))
df.iloc[2:7,0] = np.nan
df.iloc[3:5,2] = np.nan

expected = df.copy()
expected.iloc[2,0] = 999
expected.iloc[3,2] = 999
result = df.fillna(999,limit=1)
assert_frame_equal(result, expected)

def test_fillna_dtype_conversion(self):
# make sure that fillna on an empty frame works
df = DataFrame(index=["A","B","C"], columns = [1,2,3,4,5])
Expand Down
5 changes: 5 additions & 0 deletions pandas/tests/test_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -1322,6 +1322,11 @@ def test_fillna(self):
self.assertRaises(TypeError, self.panel.fillna, [1, 2])
self.assertRaises(TypeError, self.panel.fillna, (1, 2))

# limit not implemented when only value is specified
p = Panel(np.random.randn(3,4,5))
p.iloc[0:2,0:2,0:2] = np.nan
self.assertRaises(NotImplementedError, lambda : p.fillna(999,limit=1))

def test_ffill_bfill(self):
assert_panel_equal(self.panel.ffill(),
self.panel.fillna(method='ffill'))
Expand Down
10 changes: 10 additions & 0 deletions pandas/tests/test_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -2941,6 +2941,16 @@ def test_fillna(self):
expected = Series([0,0,2.], list('bac'))
assert_series_equal(result,expected)

# limit
s = Series(np.nan,index=[0,1,2])
result = s.fillna(999,limit=1)
expected = Series([999,np.nan,np.nan],index=[0,1,2])
assert_series_equal(result,expected)

result = s.fillna(999,limit=2)
expected = Series([999,999,np.nan],index=[0,1,2])
assert_series_equal(result,expected)

def test_fillna_bug(self):
x = Series([nan, 1., nan, 3., nan], ['z', 'a', 'b', 'c', 'd'])
filled = x.fillna(method='ffill')
Expand Down

0 comments on commit e19b2eb

Please sign in to comment.