Skip to content

Commit 5e64e88

Browse files
committed
Merge pull request #6365 from cpcloud/replace-nested-dict-6342
BUG: fix nested dict replace
2 parents 709e45e + 4abf0d1 commit 5e64e88

File tree

4 files changed

+31
-9
lines changed

4 files changed

+31
-9
lines changed

doc/source/release.rst

+2
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ Bug Fixes
113113
- Bug correctly handle placements of ``-inf`` in Panels when dividing by integer 0 (:issue:`6178`)
114114
- ``DataFrame.shift`` with ``axis=1`` was raising (:issue:`6371`)
115115
- Disabled clipboard tests until release time (run locally with ``nosetests -A disabled`` (:issue:`6048`).
116+
- Bug in ``DataFrame.replace()`` when passing a nested ``dict`` that contained
117+
keys not in the values to be replaced (:issue:`6342`)
116118

117119
pandas 0.13.1
118120
-------------

pandas/core/generic.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -2330,8 +2330,8 @@ def replace(self, to_replace=None, value=None, inplace=False, limit=None,
23302330
value_dict = {}
23312331

23322332
for k, v in items:
2333-
to_rep_dict[k] = v.keys()
2334-
value_dict[k] = v.values()
2333+
to_rep_dict[k] = list(v.keys())
2334+
value_dict[k] = list(v.values())
23352335

23362336
to_replace, value = to_rep_dict, value_dict
23372337
else:
@@ -2349,7 +2349,6 @@ def replace(self, to_replace=None, value=None, inplace=False, limit=None,
23492349
new_data = self._data
23502350
if is_dictlike(to_replace):
23512351
if is_dictlike(value): # {'A' : NA} -> {'A' : 0}
2352-
new_data = self._data
23532352
for c, src in compat.iteritems(to_replace):
23542353
if c in value and c in self:
23552354
new_data = new_data.replace(to_replace=src,
@@ -2360,7 +2359,6 @@ def replace(self, to_replace=None, value=None, inplace=False, limit=None,
23602359

23612360
# {'A': NA} -> 0
23622361
elif not com.is_list_like(value):
2363-
new_data = self._data
23642362
for k, src in compat.iteritems(to_replace):
23652363
if k in self:
23662364
new_data = new_data.replace(to_replace=src,

pandas/core/internals.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,7 @@ def putmask(self, mask, new, align=True, inplace=False):
729729
def create_block(v, m, n, item, reshape=True):
730730
""" return a new block, try to preserve dtype if possible """
731731

732-
# n should the length of the mask or a scalar here
732+
# n should be the length of the mask or a scalar here
733733
if not is_list_like(n):
734734
n = np.array([n] * len(m))
735735

@@ -742,7 +742,7 @@ def create_block(v, m, n, item, reshape=True):
742742
if (nn == nn_at).all():
743743
nv = v.copy()
744744
nv[mask] = nn_at
745-
except:
745+
except (ValueError, IndexError, TypeError):
746746
pass
747747

748748
# change the dtype
@@ -751,8 +751,10 @@ def create_block(v, m, n, item, reshape=True):
751751
nv = v.astype(dtype)
752752
try:
753753
nv[m] = n
754-
except:
755-
np.putmask(nv, m, n)
754+
except ValueError:
755+
idx, = np.where(np.squeeze(m))
756+
for mask_index, new_val in zip(idx, n):
757+
nv[mask_index] = new_val
756758

757759
if reshape:
758760
nv = _block_shape(nv)

pandas/tests/test_frame.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -7804,6 +7804,27 @@ def test_replace_mixed(self):
78047804
expected.iloc[1,1] = m[1]
78057805
assert_frame_equal(result,expected)
78067806

7807+
def test_replace_simple_nested_dict(self):
7808+
df = DataFrame({'col': range(1, 5)})
7809+
expected = DataFrame({'col': ['a', 2, 3, 'b']})
7810+
7811+
result = df.replace({'col': {1: 'a', 4: 'b'}})
7812+
tm.assert_frame_equal(expected, result)
7813+
7814+
# in this case, should be the same as the not nested version
7815+
result = df.replace({1: 'a', 4: 'b'})
7816+
tm.assert_frame_equal(expected, result)
7817+
7818+
def test_replace_simple_nested_dict_with_nonexistent_value(self):
7819+
df = DataFrame({'col': range(1, 5)})
7820+
expected = DataFrame({'col': ['a', 2, 3, 'b']})
7821+
7822+
result = df.replace({-1: '-', 1: 'a', 4: 'b'})
7823+
tm.assert_frame_equal(expected, result)
7824+
7825+
result = df.replace({'col': {-1: '-', 1: 'a', 4: 'b'}})
7826+
tm.assert_frame_equal(expected, result)
7827+
78077828
def test_interpolate(self):
78087829
pass
78097830

@@ -12148,7 +12169,6 @@ def check_query_with_named_multiindex(self, parser, engine):
1214812169
name='color')
1214912170

1215012171
# equality
12151-
#import ipdb; ipdb.set_trace()
1215212172
res1 = df.query('color == "red"', parser=parser, engine=engine)
1215312173
res2 = df.query('"red" == color', parser=parser, engine=engine)
1215412174
exp = df[ind == 'red']

0 commit comments

Comments
 (0)