Skip to content

Commit 031cf19

Browse files
committed
TST: add tests/test_generic.py
API/CLN: Refactor rename methods to core/generic.py; fixes Series.rename for (GH4605), and adds rename with the same signature for ``Panel`` API/CLN: Refactor Series.copy to core/generic.py; removes the order argument from Series.copy (inconsistent)
1 parent 9ea0d44 commit 031cf19

File tree

8 files changed

+195
-173
lines changed

8 files changed

+195
-173
lines changed

doc/source/api.rst

+1
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,7 @@ Reindexing / Selection / Label manipulation
730730
Panel.reindex
731731
Panel.reindex_axis
732732
Panel.reindex_like
733+
Panel.rename
733734
Panel.select
734735
Panel.take
735736
Panel.truncate

doc/source/release.rst

+4-6
Original file line numberDiff line numberDiff line change
@@ -172,21 +172,19 @@ See :ref:`Internal Refactoring<whatsnew_0130.refactoring>`
172172

173173
- added ``ftypes`` method to Series/DataFame, similar to ``dtypes``, but indicates
174174
if the underlying is sparse/dense (as well as the dtype)
175-
176175
- All ``NDFrame`` objects now have a ``_prop_attributes``, which can be used to indcated various
177176
values to propogate to a new object from an existing (e.g. name in ``Series`` will follow
178177
more automatically now)
179-
180178
- Internal type checking is now done via a suite of generated classes, allowing ``isinstance(value, klass)``
181179
without having to directly import the klass, courtesy of @jtratner
182-
183180
- Bug in Series update where the parent frame is not updating its cache based on
184181
changes (:issue:`4080`) or types (:issue:`3217`), fillna (:issue:`3386`)
185-
186182
- Indexing with dtype conversions fixed (:issue:`4463`, :issue:`4204`)
187-
188-
- Refactor Series.reindex to core/generic.py (:issue:`4604`, :issue:`4618`), allow ``method=`` in reindexing
183+
- Refactor ``Series.reindex`` to core/generic.py (:issue:`4604`, :issue:`4618`), allow ``method=`` in reindexing
189184
on a Series to work
185+
- ``Series.copy`` no longer accepts the ``order`` parameter and is now consistent with ``NDFrame`` copy
186+
- Refactor ``rename`` methods to core/generic.py; fixes ``Series.rename`` for (:issue`4605`), and adds ``rename``
187+
with the same signature for ``Panel``
190188

191189
**Experimental Features**
192190

doc/source/v0.13.0.txt

+4-6
Original file line numberDiff line numberDiff line change
@@ -226,21 +226,19 @@ and behaviors. Series formerly subclassed directly from ``ndarray``. (:issue:`40
226226

227227
- added ``ftypes`` method to Series/DataFame, similar to ``dtypes``, but indicates
228228
if the underlying is sparse/dense (as well as the dtype)
229-
230229
- All ``NDFrame`` objects now have a ``_prop_attributes``, which can be used to indcated various
231230
values to propogate to a new object from an existing (e.g. name in ``Series`` will follow
232231
more automatically now)
233-
234232
- Internal type checking is now done via a suite of generated classes, allowing ``isinstance(value, klass)``
235233
without having to directly import the klass, courtesy of @jtratner
236-
237234
- Bug in Series update where the parent frame is not updating its cache based on
238235
changes (:issue:`4080`) or types (:issue:`3217`), fillna (:issue:`3386`)
239-
240236
- Indexing with dtype conversions fixed (:issue:`4463`, :issue:`4204`)
241-
242-
- Refactor Series.reindex to core/generic.py (:issue:`4604`, :issue:`4618`), allow ``method=`` in reindexing
237+
- Refactor ``Series.reindex`` to core/generic.py (:issue:`4604`, :issue:`4618`), allow ``method=`` in reindexing
243238
on a Series to work
239+
- ``Series.copy`` no longer accepts the ``order`` parameter and is now consistent with ``NDFrame`` copy
240+
- Refactor ``rename`` methods to core/generic.py; fixes ``Series.rename`` for (:issue`4605`), and adds ``rename``
241+
with the same signature for ``Panel``
244242

245243
Bug Fixes
246244
~~~~~~~~~

pandas/core/frame.py

-58
Original file line numberDiff line numberDiff line change
@@ -2897,64 +2897,6 @@ def reorder_levels(self, order, axis=0):
28972897
result.columns = result.columns.reorder_levels(order)
28982898
return result
28992899

2900-
#----------------------------------------------------------------------
2901-
# Rename
2902-
2903-
def rename(self, index=None, columns=None, copy=True, inplace=False):
2904-
"""
2905-
Alter index and / or columns using input function or
2906-
functions. Function / dict values must be unique (1-to-1). Labels not
2907-
contained in a dict / Series will be left as-is.
2908-
2909-
Parameters
2910-
----------
2911-
index : dict-like or function, optional
2912-
Transformation to apply to index values
2913-
columns : dict-like or function, optional
2914-
Transformation to apply to column values
2915-
copy : boolean, default True
2916-
Also copy underlying data
2917-
inplace : boolean, default False
2918-
Whether to return a new DataFrame. If True then value of copy is
2919-
ignored.
2920-
2921-
See also
2922-
--------
2923-
Series.rename
2924-
2925-
Returns
2926-
-------
2927-
renamed : DataFrame (new object)
2928-
"""
2929-
from pandas.core.series import _get_rename_function
2930-
2931-
if index is None and columns is None:
2932-
raise Exception('must pass either index or columns')
2933-
2934-
index_f = _get_rename_function(index)
2935-
columns_f = _get_rename_function(columns)
2936-
2937-
self._consolidate_inplace()
2938-
2939-
result = self if inplace else self.copy(deep=copy)
2940-
2941-
if index is not None:
2942-
result._rename_index_inplace(index_f)
2943-
2944-
if columns is not None:
2945-
result._rename_columns_inplace(columns_f)
2946-
2947-
if not inplace:
2948-
return result
2949-
2950-
def _rename_index_inplace(self, mapper):
2951-
self._data = self._data.rename_axis(mapper, axis=1)
2952-
self._clear_item_cache()
2953-
2954-
def _rename_columns_inplace(self, mapper):
2955-
self._data = self._data.rename_items(mapper, copydata=False)
2956-
self._clear_item_cache()
2957-
29582900
#----------------------------------------------------------------------
29592901
# Arithmetic / combination related
29602902

pandas/core/generic.py

+80-17
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@
1313
from pandas.core.internals import BlockManager
1414
import pandas.core.common as com
1515
from pandas import compat
16-
from pandas.compat import map, zip
16+
from pandas.compat import map, zip, lrange
1717
from pandas.core.common import (isnull, notnull, is_list_like,
1818
_values_from_object,
19-
_infer_dtype_from_scalar, _maybe_promote)
19+
_infer_dtype_from_scalar, _maybe_promote,
20+
ABCSeries)
2021

2122
class NDFrame(PandasObject):
2223

@@ -382,7 +383,77 @@ def swaplevel(self, i, j, axis=0):
382383
result._data.set_axis(axis, labels.swaplevel(i, j))
383384
return result
384385

385-
def rename_axis(self, mapper, axis=0, copy=True):
386+
#----------------------------------------------------------------------
387+
# Rename
388+
389+
def rename(self, *args, **kwargs):
390+
"""
391+
Alter axes input function or
392+
functions. Function / dict values must be unique (1-to-1). Labels not
393+
contained in a dict / Series will be left as-is.
394+
395+
Parameters
396+
----------
397+
axis keywords for this object
398+
(e.g. index for Series,
399+
index,columns for DataFrame,
400+
items,major_axis,minor_axis for Panel)
401+
: dict-like or function, optional
402+
Transformation to apply to that axis values
403+
404+
copy : boolean, default True
405+
Also copy underlying data
406+
inplace : boolean, default False
407+
Whether to return a new PandasObject. If True then value of copy is
408+
ignored.
409+
410+
Returns
411+
-------
412+
renamed : PandasObject (new object)
413+
"""
414+
415+
axes, kwargs = self._construct_axes_from_arguments(args, kwargs)
416+
copy = kwargs.get('copy', True)
417+
inplace = kwargs.get('inplace', False)
418+
419+
if (com._count_not_none(*axes.values()) == 0):
420+
raise Exception('must pass an index to rename')
421+
422+
# renamer function if passed a dict
423+
def _get_rename_function(mapper):
424+
if isinstance(mapper, (dict, ABCSeries)):
425+
def f(x):
426+
if x in mapper:
427+
return mapper[x]
428+
else:
429+
return x
430+
else:
431+
f = mapper
432+
433+
return f
434+
435+
436+
self._consolidate_inplace()
437+
result = self if inplace else self.copy(deep=copy)
438+
439+
# start in the axis order to eliminate too many copies
440+
for axis in lrange(self._AXIS_LEN):
441+
v = axes.get(self._AXIS_NAMES[axis])
442+
if v is None: continue
443+
f = _get_rename_function(v)
444+
445+
baxis = self._get_block_manager_axis(axis)
446+
result._data = result._data.rename(f, axis=baxis, copy=copy)
447+
result._clear_item_cache()
448+
449+
if inplace:
450+
self._data = result._data
451+
self._clear_item_cache()
452+
453+
else:
454+
return result._propogate_attributes(self)
455+
456+
def rename_axis(self, mapper, axis=0, copy=True, inplace=False):
386457
"""
387458
Alter index and / or columns using input function or functions.
388459
Function / dict values must be unique (1-to-1). Labels not contained in
@@ -394,24 +465,16 @@ def rename_axis(self, mapper, axis=0, copy=True):
394465
axis : int, default 0
395466
copy : boolean, default True
396467
Also copy underlying data
468+
inplace : boolean, default False
397469
398470
Returns
399471
-------
400472
renamed : type of caller
401473
"""
402-
# should move this at some point
403-
from pandas.core.series import _get_rename_function
404-
405-
mapper_f = _get_rename_function(mapper)
406-
407-
if axis == 0:
408-
new_data = self._data.rename_items(mapper_f, copydata=copy)
409-
else:
410-
new_data = self._data.rename_axis(mapper_f, axis=axis)
411-
if copy:
412-
new_data = new_data.copy()
413-
414-
return self._constructor(new_data)
474+
axis = self._AXIS_NAMES[axis]
475+
d = { 'copy' : copy, 'inplace' : inplace }
476+
d[axis] = mapper
477+
return self.rename(**d)
415478

416479
#----------------------------------------------------------------------
417480
# Comparisons
@@ -1373,7 +1436,7 @@ def copy(self, deep=True):
13731436
data = self._data
13741437
if deep:
13751438
data = data.copy()
1376-
return self._constructor(data)
1439+
return self._constructor(data)._propogate_attributes(self)
13771440

13781441
def convert_objects(self, convert_dates=True, convert_numeric=False, copy=True):
13791442
"""

pandas/core/internals.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -2758,8 +2758,8 @@ def rrenamer(x):
27582758
return '%s%s' % (x, rsuffix)
27592759
return x
27602760

2761-
this = self.rename_items(lrenamer, copydata=copydata)
2762-
other = other.rename_items(rrenamer, copydata=copydata)
2761+
this = self.rename_items(lrenamer, copy=copydata)
2762+
other = other.rename_items(rrenamer, copy=copydata)
27632763
else:
27642764
this = self
27652765

@@ -2777,6 +2777,13 @@ def _is_indexed_like(self, other):
27772777
return False
27782778
return True
27792779

2780+
def rename(self, mapper, axis, copy=False):
2781+
""" generic rename """
2782+
2783+
if axis == 0:
2784+
return self.rename_items(mapper, copy=copy)
2785+
return self.rename_axis(mapper, axis=axis)
2786+
27802787
def rename_axis(self, mapper, axis=1):
27812788

27822789
index = self.axes[axis]
@@ -2793,7 +2800,7 @@ def rename_axis(self, mapper, axis=1):
27932800
new_axes[axis] = new_axis
27942801
return self.__class__(self.blocks, new_axes)
27952802

2796-
def rename_items(self, mapper, copydata=True):
2803+
def rename_items(self, mapper, copy=True):
27972804
if isinstance(self.items, MultiIndex):
27982805
items = [tuple(mapper(y) for y in x) for x in self.items]
27992806
new_items = MultiIndex.from_tuples(items, names=self.items.names)
@@ -2803,7 +2810,7 @@ def rename_items(self, mapper, copydata=True):
28032810

28042811
new_blocks = []
28052812
for block in self.blocks:
2806-
newb = block.copy(deep=copydata)
2813+
newb = block.copy(deep=copy)
28072814
newb.set_ref_items(new_items, maybe_rename=True)
28082815
new_blocks.append(newb)
28092816
new_axes = list(self.axes)

0 commit comments

Comments
 (0)