Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 618c253

Browse files
committedNov 22, 2017
Move replace back to generic.py
1 parent d3f9a4a commit 618c253

File tree

3 files changed

+167
-346
lines changed

3 files changed

+167
-346
lines changed
 

‎pandas/core/frame.py

Lines changed: 5 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -232,30 +232,6 @@
232232
233233
"""
234234

235-
def _single_replace(self, to_replace, method, inplace, limit):
236-
if self.ndim != 1:
237-
raise TypeError('cannot replace {0} with method {1} on a {2}'
238-
.format(to_replace, method, type(self).__name__))
239-
240-
orig_dtype = self.dtype
241-
result = self if inplace else self.copy()
242-
fill_f = missing.get_fill_func(method)
243-
244-
mask = missing.mask_missing(result.values, to_replace)
245-
values = fill_f(result.values, limit=limit, mask=mask)
246-
247-
if values.dtype == orig_dtype and inplace:
248-
return
249-
250-
result = pd.Series(values, index=self.index,
251-
dtype=self.dtype).__finalize__(self)
252-
253-
if inplace:
254-
self._update_inplace(result._data)
255-
return
256-
257-
return result
258-
259235
# -----------------------------------------------------------------------
260236
# DataFrame class
261237

@@ -3142,8 +3118,8 @@ def replace(self, to_replace=None, value=None, inplace=False, limit=None,
31423118
31433119
See Also
31443120
--------
3145-
:func:`DataFrame.fillna` : Fill NA/NaN values
3146-
:func:`DataFrame.where` : Replace values based on boolean condition
3121+
DataFrame.fillna : Fill NA/NaN values
3122+
DataFrame.where : Replace values based on boolean condition
31473123
31483124
Returns
31493125
-------
@@ -3269,153 +3245,9 @@ def replace(self, to_replace=None, value=None, inplace=False, limit=None,
32693245
the correct type for replacement.
32703246
32713247
"""
3272-
inplace = validate_bool_kwarg(inplace, 'inplace')
3273-
if not is_bool(regex) and to_replace is not None:
3274-
raise AssertionError("'to_replace' must be 'None' if 'regex' is "
3275-
"not a bool")
3276-
if axis is not None:
3277-
warnings.warn('the "axis" argument is deprecated '
3278-
'and will be removed in'
3279-
'v0.13; this argument has no effect')
3280-
3281-
self._consolidate_inplace()
3282-
3283-
if value is None:
3284-
# passing a single value that is scalar like
3285-
# when value is None (GH5319), for compat
3286-
if not is_dict_like(to_replace) and not is_dict_like(regex):
3287-
to_replace = [to_replace]
3288-
3289-
if isinstance(to_replace, (tuple, list)):
3290-
return _single_replace(self, to_replace, method, inplace,
3291-
limit)
3292-
3293-
if not is_dict_like(to_replace):
3294-
if not is_dict_like(regex):
3295-
raise TypeError('If "to_replace" and "value" are both None'
3296-
' and "to_replace" is not a list, then '
3297-
'regex must be a mapping')
3298-
to_replace = regex
3299-
regex = True
3300-
3301-
items = list(compat.iteritems(to_replace))
3302-
keys, values = lzip(*items) or ([], [])
3303-
3304-
are_mappings = [is_dict_like(v) for v in values]
3305-
3306-
if any(are_mappings):
3307-
if not all(are_mappings):
3308-
raise TypeError("If a nested mapping is passed, all values"
3309-
" of the top level mapping must be "
3310-
"mappings")
3311-
# passed a nested dict/Series
3312-
to_rep_dict = {}
3313-
value_dict = {}
3314-
3315-
for k, v in items:
3316-
keys, values = lzip(*v.items()) or ([], [])
3317-
if set(keys) & set(values):
3318-
raise ValueError("Replacement not allowed with "
3319-
"overlapping keys and values")
3320-
to_rep_dict[k] = list(keys)
3321-
value_dict[k] = list(values)
3322-
3323-
to_replace, value = to_rep_dict, value_dict
3324-
else:
3325-
to_replace, value = keys, values
3326-
3327-
return self.replace(to_replace, value, inplace=inplace,
3328-
limit=limit, regex=regex)
3329-
else:
3330-
3331-
# need a non-zero len on all axes
3332-
for a in self._AXIS_ORDERS:
3333-
if not len(self._get_axis(a)):
3334-
return self
3335-
3336-
new_data = self._data
3337-
if is_dict_like(to_replace):
3338-
if is_dict_like(value): # {'A' : NA} -> {'A' : 0}
3339-
res = self if inplace else self.copy()
3340-
for c, src in compat.iteritems(to_replace):
3341-
if c in value and c in self:
3342-
# object conversion is handled in
3343-
# series.replace which is called recursivelly
3344-
res[c] = res[c].replace(to_replace=src,
3345-
value=value[c],
3346-
inplace=False,
3347-
regex=regex)
3348-
return None if inplace else res
3349-
3350-
# {'A': NA} -> 0
3351-
elif not is_list_like(value):
3352-
keys = [(k, src) for k, src in compat.iteritems(to_replace)
3353-
if k in self]
3354-
keys_len = len(keys) - 1
3355-
for i, (k, src) in enumerate(keys):
3356-
convert = i == keys_len
3357-
new_data = new_data.replace(to_replace=src,
3358-
value=value,
3359-
filter=[k],
3360-
inplace=inplace,
3361-
regex=regex,
3362-
convert=convert)
3363-
else:
3364-
raise TypeError('value argument must be scalar, dict, or '
3365-
'Series')
3366-
3367-
elif is_list_like(to_replace): # [NA, ''] -> [0, 'missing']
3368-
if is_list_like(value):
3369-
if len(to_replace) != len(value):
3370-
raise ValueError('Replacement lists must match '
3371-
'in length. Expecting %d got %d ' %
3372-
(len(to_replace), len(value)))
3373-
3374-
new_data = self._data.replace_list(src_list=to_replace,
3375-
dest_list=value,
3376-
inplace=inplace,
3377-
regex=regex)
3378-
3379-
else: # [NA, ''] -> 0
3380-
new_data = self._data.replace(to_replace=to_replace,
3381-
value=value, inplace=inplace,
3382-
regex=regex)
3383-
elif to_replace is None:
3384-
if not (is_re_compilable(regex) or
3385-
is_list_like(regex) or is_dict_like(regex)):
3386-
raise TypeError("'regex' must be a string or a compiled "
3387-
"regular expression or a list or dict of "
3388-
"strings or regular expressions, you "
3389-
"passed a"
3390-
" {0!r}".format(type(regex).__name__))
3391-
return self.replace(regex, value, inplace=inplace, limit=limit,
3392-
regex=True)
3393-
else:
3394-
3395-
# dest iterable dict-like
3396-
if is_dict_like(value): # NA -> {'A' : 0, 'B' : -1}
3397-
new_data = self._data
3398-
3399-
for k, v in compat.iteritems(value):
3400-
if k in self:
3401-
new_data = new_data.replace(to_replace=to_replace,
3402-
value=v, filter=[k],
3403-
inplace=inplace,
3404-
regex=regex)
3405-
3406-
elif not is_list_like(value): # NA -> 0
3407-
new_data = self._data.replace(to_replace=to_replace,
3408-
value=value, inplace=inplace,
3409-
regex=regex)
3410-
else:
3411-
msg = ('Invalid "to_replace" type: '
3412-
'{0!r}').format(type(to_replace).__name__)
3413-
raise TypeError(msg) # pragma: no cover
3414-
3415-
if inplace:
3416-
self._update_inplace(new_data)
3417-
else:
3418-
return self._constructor(new_data).__finalize__(self)
3248+
return super(DataFrame, self).replace(to_replace=to_replace,
3249+
value=value, inplace=inplace, limit=limit, regex=regex,
3250+
method=method, axis=axis)
34193251

34203252
@Appender(_shared_docs['shift'] % _shared_doc_kwargs)
34213253
def shift(self, periods=1, freq=None, axis=0):

‎pandas/core/generic.py

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@
7272

7373

7474
def _single_replace(self, to_replace, method, inplace, limit):
75+
"""
76+
Replaces values in a Series using the fill method specified when no
77+
replacement value is given in the replace method
78+
"""
7579
if self.ndim != 1:
7680
raise TypeError('cannot replace {0} with method {1} on a {2}'
7781
.format(to_replace, method, type(self).__name__))
@@ -4354,6 +4358,159 @@ def bfill(self, axis=None, inplace=False, limit=None, downcast=None):
43544358
return self.fillna(method='bfill', axis=axis, inplace=inplace,
43554359
limit=limit, downcast=downcast)
43564360

4361+
def replace(self, to_replace=None, value=None, inplace=False, limit=None,
4362+
regex=False, method='pad', axis=None):
4363+
"""
4364+
Replace values given in 'to_replace' with 'value'
4365+
"""
4366+
inplace = validate_bool_kwarg(inplace, 'inplace')
4367+
if not is_bool(regex) and to_replace is not None:
4368+
raise AssertionError("'to_replace' must be 'None' if 'regex' is "
4369+
"not a bool")
4370+
if axis is not None:
4371+
warnings.warn('the "axis" argument is deprecated '
4372+
'and will be removed in'
4373+
'v0.13; this argument has no effect')
4374+
4375+
self._consolidate_inplace()
4376+
4377+
if value is None:
4378+
# passing a single value that is scalar like
4379+
# when value is None (GH5319), for compat
4380+
if not is_dict_like(to_replace) and not is_dict_like(regex):
4381+
to_replace = [to_replace]
4382+
4383+
if isinstance(to_replace, (tuple, list)):
4384+
return _single_replace(self, to_replace, method, inplace,
4385+
limit)
4386+
4387+
if not is_dict_like(to_replace):
4388+
if not is_dict_like(regex):
4389+
raise TypeError('If "to_replace" and "value" are both None'
4390+
' and "to_replace" is not a list, then '
4391+
'regex must be a mapping')
4392+
to_replace = regex
4393+
regex = True
4394+
4395+
items = list(compat.iteritems(to_replace))
4396+
keys, values = lzip(*items) or ([], [])
4397+
4398+
are_mappings = [is_dict_like(v) for v in values]
4399+
4400+
if any(are_mappings):
4401+
if not all(are_mappings):
4402+
raise TypeError("If a nested mapping is passed, all values"
4403+
" of the top level mapping must be "
4404+
"mappings")
4405+
# passed a nested dict/Series
4406+
to_rep_dict = {}
4407+
value_dict = {}
4408+
4409+
for k, v in items:
4410+
keys, values = lzip(*v.items()) or ([], [])
4411+
if set(keys) & set(values):
4412+
raise ValueError("Replacement not allowed with "
4413+
"overlapping keys and values")
4414+
to_rep_dict[k] = list(keys)
4415+
value_dict[k] = list(values)
4416+
4417+
to_replace, value = to_rep_dict, value_dict
4418+
else:
4419+
to_replace, value = keys, values
4420+
4421+
return self.replace(to_replace, value, inplace=inplace,
4422+
limit=limit, regex=regex)
4423+
else:
4424+
4425+
# need a non-zero len on all axes
4426+
for a in self._AXIS_ORDERS:
4427+
if not len(self._get_axis(a)):
4428+
return self
4429+
4430+
new_data = self._data
4431+
if is_dict_like(to_replace):
4432+
if is_dict_like(value): # {'A' : NA} -> {'A' : 0}
4433+
res = self if inplace else self.copy()
4434+
for c, src in compat.iteritems(to_replace):
4435+
if c in value and c in self:
4436+
# object conversion is handled in
4437+
# series.replace which is called recursivelly
4438+
res[c] = res[c].replace(to_replace=src,
4439+
value=value[c],
4440+
inplace=False,
4441+
regex=regex)
4442+
return None if inplace else res
4443+
4444+
# {'A': NA} -> 0
4445+
elif not is_list_like(value):
4446+
keys = [(k, src) for k, src in compat.iteritems(to_replace)
4447+
if k in self]
4448+
keys_len = len(keys) - 1
4449+
for i, (k, src) in enumerate(keys):
4450+
convert = i == keys_len
4451+
new_data = new_data.replace(to_replace=src,
4452+
value=value,
4453+
filter=[k],
4454+
inplace=inplace,
4455+
regex=regex,
4456+
convert=convert)
4457+
else:
4458+
raise TypeError('value argument must be scalar, dict, or '
4459+
'Series')
4460+
4461+
elif is_list_like(to_replace): # [NA, ''] -> [0, 'missing']
4462+
if is_list_like(value):
4463+
if len(to_replace) != len(value):
4464+
raise ValueError('Replacement lists must match '
4465+
'in length. Expecting %d got %d ' %
4466+
(len(to_replace), len(value)))
4467+
4468+
new_data = self._data.replace_list(src_list=to_replace,
4469+
dest_list=value,
4470+
inplace=inplace,
4471+
regex=regex)
4472+
4473+
else: # [NA, ''] -> 0
4474+
new_data = self._data.replace(to_replace=to_replace,
4475+
value=value, inplace=inplace,
4476+
regex=regex)
4477+
elif to_replace is None:
4478+
if not (is_re_compilable(regex) or
4479+
is_list_like(regex) or is_dict_like(regex)):
4480+
raise TypeError("'regex' must be a string or a compiled "
4481+
"regular expression or a list or dict of "
4482+
"strings or regular expressions, you "
4483+
"passed a"
4484+
" {0!r}".format(type(regex).__name__))
4485+
return self.replace(regex, value, inplace=inplace, limit=limit,
4486+
regex=True)
4487+
else:
4488+
4489+
# dest iterable dict-like
4490+
if is_dict_like(value): # NA -> {'A' : 0, 'B' : -1}
4491+
new_data = self._data
4492+
4493+
for k, v in compat.iteritems(value):
4494+
if k in self:
4495+
new_data = new_data.replace(to_replace=to_replace,
4496+
value=v, filter=[k],
4497+
inplace=inplace,
4498+
regex=regex)
4499+
4500+
elif not is_list_like(value): # NA -> 0
4501+
new_data = self._data.replace(to_replace=to_replace,
4502+
value=value, inplace=inplace,
4503+
regex=regex)
4504+
else:
4505+
msg = ('Invalid "to_replace" type: '
4506+
'{0!r}').format(type(to_replace).__name__)
4507+
raise TypeError(msg) # pragma: no cover
4508+
4509+
if inplace:
4510+
self._update_inplace(new_data)
4511+
else:
4512+
return self._constructor(new_data).__finalize__(self)
4513+
43574514
_shared_docs['interpolate'] = """
43584515
Please note that only ``method='linear'`` is supported for
43594516
DataFrames/Series with a MultiIndex.

‎pandas/core/series.py

Lines changed: 5 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -117,30 +117,6 @@ def wrapper(self):
117117

118118
return wrapper
119119

120-
def _single_replace(self, to_replace, method, inplace, limit):
121-
if self.ndim != 1:
122-
raise TypeError('cannot replace {0} with method {1} on a {2}'
123-
.format(to_replace, method, type(self).__name__))
124-
125-
orig_dtype = self.dtype
126-
result = self if inplace else self.copy()
127-
fill_f = missing.get_fill_func(method)
128-
129-
mask = missing.mask_missing(result.values, to_replace)
130-
values = fill_f(result.values, limit=limit, mask=mask)
131-
132-
if values.dtype == orig_dtype and inplace:
133-
return
134-
135-
result = pd.Series(values, index=self.index,
136-
dtype=self.dtype).__finalize__(self)
137-
138-
if inplace:
139-
self._update_inplace(result._data)
140-
return
141-
142-
return result
143-
144120
# ----------------------------------------------------------------------
145121
# Series class
146122

@@ -2800,8 +2776,8 @@ def replace(self, to_replace=None, value=None, inplace=False, limit=None,
28002776
28012777
See Also
28022778
--------
2803-
:func:`Series.fillna` : Fill NA/NaN values
2804-
:func:`Series.where` : Replace values based on boolean condition
2779+
Series.fillna : Fill NA/NaN values
2780+
Series.where : Replace values based on boolean condition
28052781
28062782
Returns
28072783
-------
@@ -2915,153 +2891,9 @@ def replace(self, to_replace=None, value=None, inplace=False, limit=None,
29152891
the correct type for replacement.
29162892
29172893
"""
2918-
inplace = validate_bool_kwarg(inplace, 'inplace')
2919-
if not is_bool(regex) and to_replace is not None:
2920-
raise AssertionError("'to_replace' must be 'None' if 'regex' is "
2921-
"not a bool")
2922-
if axis is not None:
2923-
warnings.warn('the "axis" argument is deprecated '
2924-
'and will be removed in'
2925-
'v0.13; this argument has no effect')
2926-
2927-
self._consolidate_inplace()
2928-
2929-
if value is None:
2930-
# passing a single value that is scalar like
2931-
# when value is None (GH5319), for compat
2932-
if not is_dict_like(to_replace) and not is_dict_like(regex):
2933-
to_replace = [to_replace]
2934-
2935-
if isinstance(to_replace, (tuple, list)):
2936-
return _single_replace(self, to_replace, method, inplace,
2937-
limit)
2938-
2939-
if not is_dict_like(to_replace):
2940-
if not is_dict_like(regex):
2941-
raise TypeError('If "to_replace" and "value" are both None'
2942-
' and "to_replace" is not a list, then '
2943-
'regex must be a mapping')
2944-
to_replace = regex
2945-
regex = True
2946-
2947-
items = list(compat.iteritems(to_replace))
2948-
keys, values = lzip(*items) or ([], [])
2949-
2950-
are_mappings = [is_dict_like(v) for v in values]
2951-
2952-
if any(are_mappings):
2953-
if not all(are_mappings):
2954-
raise TypeError("If a nested mapping is passed, all values"
2955-
" of the top level mapping must be "
2956-
"mappings")
2957-
# passed a nested dict/Series
2958-
to_rep_dict = {}
2959-
value_dict = {}
2960-
2961-
for k, v in items:
2962-
keys, values = lzip(*v.items()) or ([], [])
2963-
if set(keys) & set(values):
2964-
raise ValueError("Replacement not allowed with "
2965-
"overlapping keys and values")
2966-
to_rep_dict[k] = list(keys)
2967-
value_dict[k] = list(values)
2968-
2969-
to_replace, value = to_rep_dict, value_dict
2970-
else:
2971-
to_replace, value = keys, values
2972-
2973-
return self.replace(to_replace, value, inplace=inplace,
2974-
limit=limit, regex=regex)
2975-
else:
2976-
2977-
# need a non-zero len on all axes
2978-
for a in self._AXIS_ORDERS:
2979-
if not len(self._get_axis(a)):
2980-
return self
2981-
2982-
new_data = self._data
2983-
if is_dict_like(to_replace):
2984-
if is_dict_like(value): # {'A' : NA} -> {'A' : 0}
2985-
res = self if inplace else self.copy()
2986-
for c, src in compat.iteritems(to_replace):
2987-
if c in value and c in self:
2988-
# object conversion is handled in
2989-
# series.replace which is called recursivelly
2990-
res[c] = res[c].replace(to_replace=src,
2991-
value=value[c],
2992-
inplace=False,
2993-
regex=regex)
2994-
return None if inplace else res
2995-
2996-
# {'A': NA} -> 0
2997-
elif not is_list_like(value):
2998-
keys = [(k, src) for k, src in compat.iteritems(to_replace)
2999-
if k in self]
3000-
keys_len = len(keys) - 1
3001-
for i, (k, src) in enumerate(keys):
3002-
convert = i == keys_len
3003-
new_data = new_data.replace(to_replace=src,
3004-
value=value,
3005-
filter=[k],
3006-
inplace=inplace,
3007-
regex=regex,
3008-
convert=convert)
3009-
else:
3010-
raise TypeError('value argument must be scalar, dict, or '
3011-
'Series')
3012-
3013-
elif is_list_like(to_replace): # [NA, ''] -> [0, 'missing']
3014-
if is_list_like(value):
3015-
if len(to_replace) != len(value):
3016-
raise ValueError('Replacement lists must match '
3017-
'in length. Expecting %d got %d ' %
3018-
(len(to_replace), len(value)))
3019-
3020-
new_data = self._data.replace_list(src_list=to_replace,
3021-
dest_list=value,
3022-
inplace=inplace,
3023-
regex=regex)
3024-
3025-
else: # [NA, ''] -> 0
3026-
new_data = self._data.replace(to_replace=to_replace,
3027-
value=value, inplace=inplace,
3028-
regex=regex)
3029-
elif to_replace is None:
3030-
if not (is_re_compilable(regex) or
3031-
is_list_like(regex) or is_dict_like(regex)):
3032-
raise TypeError("'regex' must be a string or a compiled "
3033-
"regular expression or a list or dict of "
3034-
"strings or regular expressions, you "
3035-
"passed a"
3036-
" {0!r}".format(type(regex).__name__))
3037-
return self.replace(regex, value, inplace=inplace, limit=limit,
3038-
regex=True)
3039-
else:
3040-
3041-
# dest iterable dict-like
3042-
if is_dict_like(value): # NA -> {'A' : 0, 'B' : -1}
3043-
new_data = self._data
3044-
3045-
for k, v in compat.iteritems(value):
3046-
if k in self:
3047-
new_data = new_data.replace(to_replace=to_replace,
3048-
value=v, filter=[k],
3049-
inplace=inplace,
3050-
regex=regex)
3051-
3052-
elif not is_list_like(value): # NA -> 0
3053-
new_data = self._data.replace(to_replace=to_replace,
3054-
value=value, inplace=inplace,
3055-
regex=regex)
3056-
else:
3057-
msg = ('Invalid "to_replace" type: '
3058-
'{0!r}').format(type(to_replace).__name__)
3059-
raise TypeError(msg) # pragma: no cover
3060-
3061-
if inplace:
3062-
self._update_inplace(new_data)
3063-
else:
3064-
return self._constructor(new_data).__finalize__(self)
2894+
return super(Series, self).replace(to_replace=to_replace, value=value,
2895+
inplace=inplace, limit=limit,
2896+
regex=regex, method=method, axis=axis)
30652897

30662898
@Appender(generic._shared_docs['shift'] % _shared_doc_kwargs)
30672899
def shift(self, periods=1, freq=None, axis=0):

0 commit comments

Comments
 (0)
Please sign in to comment.