-
-
Notifications
You must be signed in to change notification settings - Fork 18.7k
API: Added axis argument to rename, reindex #17800
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -111,20 +111,39 @@ For example: | |
# the following is now equivalent | ||
df.drop(columns=['B', 'C']) | ||
|
||
``rename`` now also accepts axis keyword | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
.. _whatsnew_0210.enhancements.rename_reindex_axis: | ||
|
||
The :meth:`~DataFrame.rename` method has gained the ``axis`` keyword as an | ||
alternative to specify the ``axis`` to target (:issue:`12392`). | ||
``rename``, ``reindex`` now also accept axis keyword | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
.. ipython:: | ||
The :meth:`DataFrame.rename` and :meth:`DataFrame.reindex` methods have gained | ||
the ``axis`` keyword to specify the axis to target with the operation | ||
(:issue:`12392`). | ||
|
||
Here's ``rename``: | ||
|
||
.. ipython:: python | ||
|
||
df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}) | ||
df.rename(str.lower, axis='columns') | ||
df.rename(id, axis='index') | ||
|
||
And ``reindex``: | ||
|
||
.. ipython:: python | ||
|
||
df.reindex(['A', 'B', 'C'], axis='columns') | ||
df.reindex([0, 1, 3], axis='index') | ||
|
||
The "index, columns" style continues to work as before. | ||
|
||
.. ipython:: python | ||
|
||
df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}) | ||
df.rename(str.lower, axis='columns') | ||
df.rename(id, axis='index') | ||
df.rename(index=id, columns=str.lower) | ||
df.reindex(index=[0, 1, 3], columns=['A', 'B', 'C']) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe add |
||
The ``.rename(index=id, columns=str.lower)`` style continues to work as before. | ||
We *highly* encourage using named arguments to avoid confusion. | ||
We *highly* encourage using named arguments to avoid confusion when using either | ||
style. | ||
|
||
.. _whatsnew_0210.enhancements.categorical_dtype: | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -65,6 +65,7 @@ | |
_values_from_object, | ||
_maybe_box_datetimelike, | ||
_dict_compat, | ||
_all_not_none, | ||
standardize_mapping) | ||
from pandas.core.generic import NDFrame, _shared_docs | ||
from pandas.core.index import (Index, MultiIndex, _ensure_index, | ||
|
@@ -112,10 +113,10 @@ | |
by : str or list of str | ||
Name or list of names which refer to the axis items.""", | ||
versionadded_to_excel='', | ||
optional_mapper="""mapper : dict-like or function | ||
Applied to the axis specified by `axis`""", | ||
optional_labels="""labels : array-like, optional | ||
New labels / index to conform the axis specified by 'axis' to.""", | ||
optional_axis="""axis : int or str, optional | ||
Axis to target. Can be either the axis name ('rows', 'columns') | ||
Axis to target. Can be either the axis name ('index', 'columns') | ||
or number (0, 1).""", | ||
) | ||
|
||
|
@@ -2801,24 +2802,25 @@ def _validate_axis_style_args(self, arg, arg_name, index, columns, | |
elif axis == 'columns': | ||
columns = arg | ||
|
||
elif all(x is not None for x in (arg, index, columns)): | ||
elif _all_not_none(arg, index, columns): | ||
msg = ( | ||
"Cannot specify all of '{arg_name}', 'index', and 'columns'. " | ||
"Specify either {arg_name} and 'axis', or 'index' and " | ||
"'columns'." | ||
).format(arg_name=arg_name) | ||
raise TypeError(msg) | ||
|
||
elif axis is None and (arg is not None and index is not None): | ||
elif _all_not_none(arg, index): | ||
# This is the "ambiguous" case, so emit a warning | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe worth factoring this function out if its common with the drop changes? not sure There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe put in pandas/util/_validators.py with all other arg validation code |
||
msg = ( | ||
"Interpreting call to '.{method_name}(a, b)' as " | ||
"'.{method_name}(index=a, columns=b)'. " | ||
"Use keyword arguments to remove any ambiguity." | ||
).format(method_name=method_name) | ||
warnings.warn(msg) | ||
warnings.warn(msg, stacklevel=3) | ||
index, columns = arg, index | ||
elif index is None and columns is None: | ||
elif index is None: | ||
# This is for the default axis, like reindex([0, 1]) | ||
index = arg | ||
<
10000
details class="details-overlay details-reset position-relative d-inline-block">
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is for the default (labels, axis=0) case ? (if so, maybe good to add a comment) |
||
return index, columns | ||
|
||
|
@@ -2948,7 +2950,11 @@ def align(self, other, join='outer', axis=None, level=None, copy=True, | |
broadcast_axis=broadcast_axis) | ||
|
||
@Appender(_shared_docs['reindex'] % _shared_doc_kwargs) | ||
def reindex(self, index=None, columns=None, **kwargs): | ||
def reindex(self, labels=None, index=None, columns=None, axis=None, | ||
**kwargs): | ||
index, columns = self._validate_axis_style_args(labels, 'labels', | ||
index, columns, | ||
axis, 'reindex') | ||
return super(DataFrame, self).reindex(index=index, columns=columns, | ||
**kwargs) | ||
|
||
|
@@ -2960,9 +2966,81 @@ def reindex_axis(self, labels, axis=0, method=None, level=None, copy=True, | |
method=method, level=level, copy=copy, | ||
limit=limit, fill_value=fill_value) | ||
|
||
@Appender(_shared_docs['rename'] % _shared_doc_kwargs) | ||
def rename(self, mapper=None, index=None, columns=None, axis=None, | ||
**kwargs): | ||
"""Alter axes labels. | ||
|
||
Function / dict values must be unique (1-to-1). Labels not contained in | ||
a dict / Series will be left as-is. Extra labels listed don't throw an | ||
error. | ||
|
||
See the :ref:`user guide <basics.rename>` for more. | ||
|
||
Parameters | ||
---------- | ||
mapper, index, columns : dict-like or function, optional | ||
dict-like or functions transformations to apply to | ||
that axis' values. Use either ``mapper`` and ``axis`` to | ||
specify the axis to target with ``mapper``, or ``index`` and | ||
``columns``. | ||
axis : int or str, optional | ||
Axis to target with ``mapper``. Can be either the axis name | ||
('index', 'columns') or number (0, 1). The default is 'index'. | ||
copy : boolean, default True | ||
Also copy underlying data | ||
inplace : boolean, default False | ||
Whether to return a new %(klass)s. If True then value of copy is | ||
ignored. | ||
level : int or level name, default None | ||
In case of a MultiIndex, only rename labels in the specified | ||
level. | ||
|
||
Returns | ||
------- | ||
renamed : DataFrame | ||
|
||
See Also | ||
-------- | ||
pandas.DataFrame.rename_axis | ||
|
||
Examples | ||
-------- | ||
|
||
``DataFrame.rename`` supports two calling conventions | ||
|
||
* ``(index=index_mapper, columns=columns_mapper, ...) | ||
* ``(mapper, axis={'index', 'columns'}, ...) | ||
|
||
We *highly* recommend using keyword arguments to clarify your | ||
intent. | ||
|
||
>>> df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}) | ||
>>> df.rename(index=str, columns={"A": "a", "B": "c"}) | ||
a c | ||
0 1 4 | ||
1 2 5 | ||
2 3 6 | ||
|
||
>>> df.rename(index=str, columns={"A": "a", "C": "c"}) | ||
a B | ||
0 1 4 | ||
1 2 5 | ||
2 3 6 | ||
|
||
Using axis-style parameters | ||
|
||
>>> df.rename(str.lower, axis='columns') | ||
a b | ||
0 1 4 | ||
1 2 5 | ||
2 3 6 | ||
|
||
>>> df.rename({1: 2, 2: 4}, axis='index') | ||
A B | ||
0 1 4 | ||
2 2 5 | ||
4 3 6 | ||
""" | ||
index, columns = self._validate_axis_style_args(mapper, 'mapper', | ||
index, columns, | ||
axis, 'rename') | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -768,6 +768,7 @@ def swaplevel(self, i=-2, j=-1, axis=0): | |
|
||
Examples | ||
-------- | ||
|
||
>>> s = pd.Series([1, 2, 3]) | ||
>>> s | ||
0 1 | ||
|
@@ -790,16 +791,29 @@ def swaplevel(self, i=-2, j=-1, axis=0): | |
5 3 | ||
dtype: int64 | ||
|
||
Since ``DataFrame`` doesn't have a ``.name`` attribute, | ||
only mapping-type arguments are allowed. | ||
|
||
>>> df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}) | ||
>>> df.rename(2) | ||
Traceback (most recent call last): | ||
... | ||
TypeError: 'int' object is not callable | ||
|
||
``DataFrame.rename`` supports two calling conventions | ||
|
||
* ``(index=index_mapper, columns=columns_mapper, ...) | ||
* ``(mapper, axis={'index', 'columns'}, ...) | ||
|
||
We *highly* recommend using keyword arguments to clarify your | ||
intent. | ||
|
||
>>> df.rename(index=str, columns={"A": "a", "B": "c"}) | ||
a c | ||
0 1 4 | ||
1 2 5 | ||
2 3 6 | ||
|
||
>>> df.rename(index=str, columns={"A": "a", "C": "c"}) | ||
a B | ||
0 1 4 | ||
|
@@ -819,6 +833,8 @@ def swaplevel(self, i=-2, j=-1, axis=0): | |
0 1 4 | ||
2 2 5 | ||
4 3 6 | ||
|
||
See the :ref:`user guide <basics.rename>` for more. | ||
""" | ||
|
||
@Appender(_shared_docs['rename'] % dict(axes='axes keywords for this' | ||
|
@@ -904,6 +920,7 @@ def rename_axis(self, mapper, axis=0, copy=True, inplace=False): | |
|
||
Examples | ||
-------- | ||
|
||
>>> df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}) | ||
>>> df.rename_axis("foo") # scalar, alters df.index.name | ||
A B | ||
|
@@ -2764,10 +2781,11 @@ def sort_index(self, axis=0, level=None, ascending=True, inplace=False, | |
|
||
Parameters | ||
---------- | ||
%(axes)s : array-like, optional (can be specified in order, or as | ||
keywords) | ||
%(optional_labels)s | ||
%(axes)s : array-like, optional (should be specified using keywords) | ||
New labels / index to conform to. Preferably an Index object to | ||
avoid duplicating data | ||
%(optional_axis)s | ||
method : {None, 'backfill'/'bfill', 'pad'/'ffill', 'nearest'}, optional | ||
method to use for filling holes in reindexed DataFrame. | ||
Please note: this is only applicable to DataFrames/Series with a | ||
|
@@ -2799,6 +2817,14 @@ def sort_index(self, axis=0, level=None, ascending=True, inplace=False, | |
Examples | ||
-------- | ||
|
||
``DataFrame.reindex`` supports two calling conventions | ||
|
||
* ``(index=index_labels, columns=column_labels, ...) | ||
* ``(labels, axis={'index', 'columns'}, ...) | ||
|
||
We *highly* recommend using keyword arguments to clarify your | ||
intent. | ||
|
||
Create a dataframe with some fictional data. | ||
|
||
>>> index = ['Firefox', 'Chrome', 'Safari', 'IE10', 'Konqueror'] | ||
|
@@ -2849,6 +2875,26 @@ def sort_index(self, axis=0, level=None, ascending=True, inplace=False, | |
IE10 404 0.08 | ||
Chrome 200 0.02 | ||
|
||
We can also reindex the columns. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same add the warning? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added above. |
||
|
||
>>> df.reindex(columns=['http_status', 'user_agent']) | ||
http_status user_agent | ||
Firefox 200 NaN | ||
Chrome 200 NaN | ||
Safari 404 NaN | ||
IE10 404 NaN | ||
Konqueror 301 NaN | ||
|
||
Or we can use "axis-style" keyword arguments | ||
|
||
>>> df.reindex(['http_status', 'user_agent'], axis="columns") | ||
http_status user_agent | ||
Firefox 200 NaN | ||
Chrome 200 NaN | ||
Safari 404 NaN | ||
IE10 404 NaN | ||
Konqueror 301 NaN | ||
|
||
To further illustrate the filling functionality in | ||
``reindex``, we will create a dataframe with a | ||
monotonically increasing index (for example, a sequence | ||
|
@@ -2911,6 +2957,8 @@ def sort_index(self, axis=0, level=None, ascending=True, inplace=False, | |
desired indexes. If you do want to fill in the ``NaN`` values present | ||
in the original dataframe, use the ``fillna()`` method. | ||
|
||
See the :ref:`user guide <basics.reindexing>` for more. | ||
|
||
Returns | ||
------- | ||
reindexed : %(klass)s | ||
|
@@ -2919,7 +2967,9 @@ def sort_index(self, axis=0, level=None, ascending=True, inplace=False, | |
# TODO: Decide if we care about having different examples for different | ||
# kinds | ||
|
||
@Appender(_shared_docs['reindex'] % dict(axes="axes", klass="NDFrame")) | ||
@Appender(_shared_docs['reindex'] % dict(axes="axes", klass="NDFrame", | ||
optional_labels="", | ||
optional_axis="")) | ||
def reindex(self, *args, **kwargs): | ||
|
||
# construct the args | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs to be same length as the title (hard to tell)