Skip to content

Commit

Permalink
API: Added axis argument to rename
Browse files Browse the repository at this point in the history
  • Loading branch information
TomAugspurger committed Oct 5, 2017
1 parent 22515f5 commit fa4358d
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 2 deletions.
13 changes: 13 additions & 0 deletions doc/source/whatsnew/v0.21.0.txt
Expand Up @@ -109,6 +109,19 @@ For example:
# the following is now equivalent
df.drop(columns=['B', 'C'])

``rename`` now also accepts axis keyword
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The :meth:`~DataFrame.rename` method has gained the ``axis`` keyword as an
alternative to specify the ``axis`` to target (:issue:`12392`).

.. ipython::

df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})
df.rename(str.lower, axis='columns')

The ``.rename(columns=str.lower)`` style continues to work as before.

.. _whatsnew_0210.enhancements.categorical_dtype:

``CategoricalDtype`` for specifying categoricals
Expand Down
23 changes: 22 additions & 1 deletion pandas/core/frame.py
Expand Up @@ -2904,7 +2904,28 @@ def reindex_axis(self, labels, axis=0, method=None, level=None, copy=True,
limit=limit, fill_value=fill_value)

@Appender(_shared_docs['rename'] % _shared_doc_kwargs)
def rename(self, index=None, columns=None, **kwargs):
def rename(self, *args, index=None, columns=None, **kwargs):
nargs = len(args)
if 'axis' in kwargs and (index is not None or columns is not None):
raise TypeError("Cannot specify 'index' or 'columns' and 'axis' at"
" the same time. Specify either\n"
"\t.rename(mapping, axis=axis), or\n"
"\t.rename(index=index, columns=columns)")
if 'axis' in kwargs and nargs > 1:
raise TypeError("Cannot specify 'index', 'axis', and 'columns' at "
"the same time.")
if nargs > 2:
raise TypeError("Too many positional arguments")

if nargs and index is not None:
raise TypeError("rename() got multiple arguments for argumnet "
"'index'")

if index is None and nargs:
index = args[0]
if columns is None and nargs > 1:
columns = args[1]

return super(DataFrame, self).rename(index=index, columns=columns,
**kwargs)

Expand Down
11 changes: 10 additions & 1 deletion pandas/core/generic.py
Expand Up @@ -807,11 +807,20 @@ def swaplevel(self, i=-2, j=-1, axis=0):
@Appender(_shared_docs['rename'] % dict(axes='axes keywords for this'
' object', klass='NDFrame'))
def rename(self, *args, **kwargs):

axes, kwargs = self._construct_axes_from_arguments(args, kwargs)
copy = kwargs.pop('copy', True)
inplace = kwargs.pop('inplace', False)
level = kwargs.pop('level', None)
axis = kwargs.pop("axis", None)

if axis:
# At this point, we know the call was
# rename(fn, axis=axis), so axes is always
# {index: op, columns: None}
axis = self._get_axis_name(axis)
op = axes['index']
axes['index'] = None
axes[axis] = op

if kwargs:
raise TypeError('rename() got an unexpected keyword '
Expand Down
60 changes: 60 additions & 0 deletions pandas/tests/frame/test_alter_axes.py
Expand Up @@ -837,6 +837,66 @@ def test_rename_objects(self):
assert 'FOO' in renamed
assert 'foo' not in renamed

def test_rename_columns(self):
df = pd.DataFrame({"A": [1, 2], "B": [1, 2]}, index=['X', 'Y'])
expected = pd.DataFrame({"a": [1, 2], "b": [1, 2]}, index=['X', 'Y'])

result = df.rename(str.lower, axis=1)
assert_frame_equal(result, expected)

result = df.rename(str.lower, axis='columns')
assert_frame_equal(result, expected)

result = df.rename({"A": 'a', 'B': 'b'}, axis=1)
assert_frame_equal(result, expected)

result = df.rename({"A": 'a', 'B': 'b'}, axis='columns')
assert_frame_equal(result, expected)

# Index
expected = pd.DataFrame({"A": [1, 2], "B": [1, 2]}, index=['x', 'y'])
result = df.rename(str.lower, axis=0)
assert_frame_equal(result, expected)

result = df.rename(str.lower, axis='index')
assert_frame_equal(result, expected)

result = df.rename({'X': 'x', 'Y': 'y'}, axis=0)
assert_frame_equal(result, expected)

result = df.rename({'X': 'x', 'Y': 'y'}, axis='index')
assert_frame_equal(result, expected)

def test_rename_raises(self):
df = pd.DataFrame({"A": [1, 2], "B": [1, 2]}, index=['0', '1'])

# Named target and axis
with tm.assert_raises_regex(TypeError, None):
df.rename(index=str.lower, axis=1)

with tm.assert_raises_regex(TypeError, None):
df.rename(index=str.lower, axis='columns')

with tm.assert_raises_regex(TypeError, None):
df.rename(index=str.lower, axis=0)

with tm.assert_raises_regex(TypeError, None):
df.rename(index=str.lower, axis='columns')

with tm.assert_raises_regex(TypeError, None):
df.rename(columns=str.lower, axis='columns')

# Multiple targets and axis
with tm.assert_raises_regex(TypeError, None):
df.rename(str.lower, str.lower, axis='columns')

# Too many targets
with tm.assert_raises_regex(TypeError, None):
df.rename(str.lower, str.lower, str.lower)

with tm.assert_raises_regex(TypeError, None):
df.rename(str.lower, index=str.lower)

def test_assign_columns(self):
self.frame['hi'] = 'there'

Expand Down

0 comments on commit fa4358d

Please sign in to comment.