Skip to content

Commit 4c8a762

Browse files
committed
Merge pull request #3072 from jreback/replace3
BUG: replace with a dict misbehaving (GH 3064), due to incorrect filtering
2 parents 9e99a5e + c466341 commit 4c8a762

File tree

3 files changed

+34
-8
lines changed

3 files changed

+34
-8
lines changed

pandas/core/frame.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -3468,8 +3468,8 @@ def replace(self, to_replace, value=None, method='pad', axis=0,
34683468
return self
34693469

34703470
new_data = self._data
3471-
if isinstance(to_replace, dict):
3472-
if isinstance(value, dict): # {'A' : NA} -> {'A' : 0}
3471+
if isinstance(to_replace, (dict, Series)):
3472+
if isinstance(value, (dict, Series)): # {'A' : NA} -> {'A' : 0}
34733473
new_data = self._data
34743474
for c, src in to_replace.iteritems():
34753475
if c in value and c in self:
@@ -3481,7 +3481,7 @@ def replace(self, to_replace, value=None, method='pad', axis=0,
34813481
if k in self:
34823482
new_data = new_data.replace(src, value, filter = [ k ], inplace=inplace)
34833483
else:
3484-
raise ValueError('Fill value must be scalar or dict')
3484+
raise ValueError('Fill value must be scalar or dict or Series')
34853485

34863486
elif isinstance(to_replace, (list, np.ndarray)):
34873487
# [NA, ''] -> [0, 'missing']
@@ -3501,7 +3501,7 @@ def replace(self, to_replace, value=None, method='pad', axis=0,
35013501
else:
35023502

35033503
# dest iterable dict-like
3504-
if isinstance(value, dict): # NA -> {'A' : 0, 'B' : -1}
3504+
if isinstance(value, (dict, Series)): # NA -> {'A' : 0, 'B' : -1}
35053505

35063506
new_data = self._data
35073507
for k, v in value.iteritems():
@@ -3528,7 +3528,7 @@ def _interpolate(self, to_replace, method, axis, inplace, limit):
35283528

35293529
method = com._clean_fill_method(method)
35303530

3531-
if isinstance(to_replace, dict):
3531+
if isinstance(to_replace, (dict, Series)):
35323532
if axis == 1:
35333533
return self.T.replace(to_replace, method=method,
35343534
limit=limit).T

pandas/core/internals.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -259,10 +259,15 @@ def _try_cast_result(self, result):
259259
we may have roundtripped thru object in the mean-time """
260260
return result
261261

262-
def replace(self, to_replace, value, inplace=False):
262+
def replace(self, to_replace, value, inplace=False, filter=None):
263263
""" replace the to_replace value with value, possible to create new blocks here
264264
this is just a call to putmask """
265265
mask = com.mask_missing(self.values, to_replace)
266+
if filter is not None:
267+
for i, item in enumerate(self.items):
268+
if item not in filter:
269+
mask[i] = False
270+
266271
if not mask.any():
267272
if inplace:
268273
return [ self ]
@@ -886,14 +891,15 @@ def apply(self, f, *args, **kwargs):
886891
----------
887892
f : the callable or function name to operate on at the block level
888893
axes : optional (if not supplied, use self.axes)
889-
filter : callable, if supplied, only call the block if the filter is True
894+
filter : list, if supplied, only call the block if the filter is in the block
890895
"""
891896

892897
axes = kwargs.pop('axes',None)
893-
filter = kwargs.pop('filter',None)
898+
filter = kwargs.get('filter')
894899
result_blocks = []
895900
for blk in self.blocks:
896901
if filter is not None:
902+
kwargs['filter'] = set(kwargs['filter'])
897903
if not blk.items.isin(filter).any():
898904
result_blocks.append(blk)
899905
continue

pandas/tests/test_frame.py

+20
Original file line numberDiff line numberDiff line change
@@ -5587,6 +5587,26 @@ def test_replace(self):
55875587
df = DataFrame(index=['a', 'b'])
55885588
assert_frame_equal(df, df.replace(5, 7))
55895589

5590+
def test_resplace_series_dict(self):
5591+
# from GH 3064
5592+
df = DataFrame({'zero': {'a': 0.0, 'b': 1}, 'one': {'a': 2.0, 'b': 0}})
5593+
result = df.replace(0, {'zero': 0.5, 'one': 1.0})
5594+
expected = DataFrame({'zero': {'a': 0.5, 'b': 1}, 'one': {'a': 2.0, 'b': 1.0}})
5595+
assert_frame_equal(result, expected)
5596+
5597+
result = df.replace(0, df.mean())
5598+
assert_frame_equal(result, expected)
5599+
5600+
# series to series/dict
5601+
df = DataFrame({'zero': {'a': 0.0, 'b': 1}, 'one': {'a': 2.0, 'b': 0}})
5602+
s = Series({'zero': 0.0, 'one': 2.0})
5603+
result = df.replace(s, {'zero': 0.5, 'one': 1.0})
5604+
expected = DataFrame({'zero': {'a': 0.5, 'b': 1}, 'one': {'a': 1.0, 'b': 0.0}})
5605+
assert_frame_equal(result, expected)
5606+
5607+
result = df.replace(s, df.mean())
5608+
assert_frame_equal(result, expected)
5609+
55905610
def test_replace_mixed(self):
55915611
self.mixed_frame['foo'][5:20] = nan
55925612
self.mixed_frame['A'][-10:] = nan

0 commit comments

Comments
 (0)