Skip to content

Commit a894ee9

Browse files
toobazalanbato
authored andcommitted
ENH: provide "inplace" argument to set_axis()
closes pandas-dev#14636 Author: Pietro Battiston <[email protected]> Closes pandas-dev#16994 from toobaz/set_axis_inplace and squashes the following commits: 8fb9d0f [Pietro Battiston] REF: adapt NDFrame.set_axis() calls to new signature 409f502 [Pietro Battiston] ENH: provide "inplace" argument to set_axis(), change signature
1 parent 2a3b8f9 commit a894ee9

File tree

7 files changed

+201
-11
lines changed

7 files changed

+201
-11
lines changed

doc/source/api.rst

+1
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ Reindexing / Selection / Label manipulation
410410
Series.reset_index
411411
Series.sample
412412
Series.select
413+
Series.set_axis
413414
Series.take
414415
Series.tail
415416
Series.truncate

doc/source/whatsnew/v0.21.0.txt

+2
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ Other Enhancements
6767
- :func:`Series.to_dict` and :func:`DataFrame.to_dict` now support an ``into`` keyword which allows you to specify the ``collections.Mapping`` subclass that you would like returned. The default is ``dict``, which is backwards compatible. (:issue:`16122`)
6868
- :func:`RangeIndex.append` now returns a ``RangeIndex`` object when possible (:issue:`16212`)
6969
- :func:`Series.rename_axis` and :func:`DataFrame.rename_axis` with ``inplace=True`` now return ``None`` while renaming the axis inplace. (:issue:`15704`)
70+
- :func:`Series.set_axis` and :func:`DataFrame.set_axis` now support the ``inplace`` parameter. (:issue:`14636`)
7071
- :func:`Series.to_pickle` and :func:`DataFrame.to_pickle` have gained a ``protocol`` parameter (:issue:`16252`). By default, this parameter is set to `HIGHEST_PROTOCOL <https://docs.python.org/3/library/pickle.html#data-stream-format>`__
7172
- :func:`api.types.infer_dtype` now infers decimals. (:issue:`15690`)
7273
- :func:`read_feather` has gained the ``nthreads`` parameter for multi-threaded operations (:issue:`16359`)
@@ -202,6 +203,7 @@ Other API Changes
202203
- ``Index.get_indexer_non_unique()`` now returns a ndarray indexer rather than an ``Index``; this is consistent with ``Index.get_indexer()`` (:issue:`16819`)
203204
- Removed the ``@slow`` decorator from ``pandas.util.testing``, which caused issues for some downstream packages' test suites. Use ``@pytest.mark.slow`` instead, which achieves the same thing (:issue:`16850`)
204205
- Moved definition of ``MergeError`` to the ``pandas.errors`` module.
206+
- The signature of :func:`Series.set_axis` and :func:`DataFrame.set_axis` has been changed from ``set_axis(axis, labels)`` to ``set_axis(labels, axis=0)``, for consistency with the rest of the API. The old signature is still supported and causes a ``FutureWarning`` to be emitted (:issue:`14636`)
205207

206208

207209
.. _whatsnew_0210.deprecations:

pandas/core/generic.py

+89-7
Original file line numberDiff line numberDiff line change
@@ -466,9 +466,91 @@ def _expand_axes(self, key):
466466

467467
return new_axes
468468

469-
def set_axis(self, axis, labels):
470-
""" public verson of axis assignment """
471-
setattr(self, self._get_axis_name(axis), labels)
469+
_shared_docs['set_axis'] = """Assign desired index to given axis
470+
471+
Parameters
472+
----------
473+
labels: list-like or Index
474+
The values for the new index
475+
axis : int or string, default 0
476+
inplace : boolean, default None
477+
Whether to return a new %(klass)s instance.
478+
479+
WARNING: inplace=None currently falls back to to True, but
480+
in a future version, will default to False. Use inplace=True
481+
explicitly rather than relying on the default.
482+
483+
.. versionadded:: 0.21.0
484+
The signature is make consistent to the rest of the API.
485+
Previously, the "axis" and "labels" arguments were respectively
486+
the first and second positional arguments.
487+
488+
Returns
489+
-------
490+
renamed : %(klass)s or None
491+
An object of same type as caller if inplace=False, None otherwise.
492+
493+
See Also
494+
--------
495+
pandas.NDFrame.rename
496+
497+
Examples
498+
--------
499+
>>> s = pd.Series([1, 2, 3])
500+
>>> s
501+
0 1
502+
1 2
503+
2 3
504+
dtype: int64
505+
>>> s.set_axis(['a', 'b', 'c'], axis=0, inplace=False)
506+
a 1
507+
b 2
508+
c 3
509+
dtype: int64
510+
>>> df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})
511+
>>> df.set_axis(['a', 'b', 'c'], axis=0, inplace=False)
512+
A B
513+
a 1 4
514+
b 2 5
515+
c 3 6
516+
>>> df.set_axis(['I', 'II'], axis=1, inplace=False)
517+
I II
518+
0 1 4
519+
1 2 5
520+
2 3 6
521+
>>> df.set_axis(['i', 'ii'], axis=1, inplace=True)
522+
>>> df
523+
i ii
524+
0 1 4
525+
1 2 5
526+
2 3 6
527+
528+
"""
529+
530+
@Appender(_shared_docs['set_axis'] % dict(klass='NDFrame'))
531+
def set_axis(self, labels, axis=0, inplace=None):
532+
if is_scalar(labels):
533+
warnings.warn(
534+
'set_axis now takes "labels" as first argument, and '
535+
'"axis" as named parameter. The old form, with "axis" as '
536+
'first parameter and \"labels\" as second, is still supported '
537+
'but will be deprecated in a future version of pandas.',
538+
FutureWarning, stacklevel=2)
539+
labels, axis = axis, labels
540+
541+
if inplace is None:
542+
warnings.warn(
543+
'set_axis currently defaults to operating inplace.\nThis '
544+
'will change in a future version of pandas, use '
545+
'inplace=True to avoid this warning.',
546+
FutureWarning, stacklevel=2)
547+
inplace = True
548+
if inplace:
549+
setattr(self, self._get_axis_name(axis), labels)
550+
else:
551+
obj = self.copy()
552+
obj.set_axis(labels, axis=axis, inplace=True)
553+
return obj
472554

473555
def _set_axis(self, axis, labels):
474556
self._data.set_axis(axis, labels)
@@ -875,7 +957,7 @@ def _set_axis_name(self, name, axis=0, inplace=False):
875957

876958
inplace = validate_bool_kwarg(inplace, 'inplace')
877959
renamed = self if inplace else self.copy()
878-
renamed.set_axis(axis, idx)
960+
renamed.set_axis(idx, axis=axis, inplace=True)
879961
if not inplace:
880962
return renamed
881963

@@ -5721,7 +5803,7 @@ def slice_shift(self, periods=1, axis=0):
57215803

57225804
new_obj = self._slice(vslicer, axis=axis)
57235805
shifted_axis = self._get_axis(axis)[islicer]
5724-
new_obj.set_axis(axis, shifted_axis)
5806+
new_obj.set_axis(shifted_axis, axis=axis, inplace=True)
57255807

57265808
return new_obj.__finalize__(self)
57275809

@@ -5881,7 +5963,7 @@ def _tz_convert(ax, tz):
58815963
ax = _tz_convert(ax, tz)
58825964

58835965
result = self._constructor(self._data, copy=copy)
5884-
result.set_axis(axis, ax)
5966+
result.set_axis(ax, axis=axis, inplace=True)
58855967
return result.__finalize__(self)
58865968

58875969
@deprecate_kwarg(old_arg_name='infer_dst', new_arg_name='ambiguous',
@@ -5949,7 +6031,7 @@ def _tz_localize(ax, tz, ambiguous):
59496031
ax = _tz_localize(ax, tz, ambiguous)
59506032

59516033
result = self._constructor(self._data, copy=copy)
5952-
result.set_axis(axis, ax)
6034+
result.set_axis(ax, axis=axis, inplace=True)
59536035
return result.__finalize__(self)
59546036

59556037
# ----------------------------------------------------------------------

pandas/core/groupby.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -530,10 +530,11 @@ def _set_result_index_ordered(self, result):
530530
if not self.grouper.is_monotonic:
531531
index = Index(np.concatenate(
532532
self._get_indices(self.grouper.result_index)))
533-
result.set_axis(self.axis, index)
533+
result.set_axis(index, axis=self.axis, inplace=True)
534534
result = result.sort_index(axis=self.axis)
535535

536-
result.set_axis(self.axis, self.obj._get_axis(self.axis))
536+
result.set_axis(self.obj._get_axis(self.axis), axis=self.axis,
537+
inplace=True)
537538
return result
538539

539540
def _dir_additions(self):

pandas/core/reshape/pivot.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,9 @@ def _all_key(key):
312312
except TypeError:
313313

314314
# we cannot reshape, so coerce the axis
315-
piece.set_axis(cat_axis, piece._get_axis(
316-
cat_axis)._to_safe_for_reshape())
315+
piece.set_axis(piece._get_axis(
316+
cat_axis)._to_safe_for_reshape(),
317+
axis=cat_axis, inplace=True)
317318
piece[all_key] = margin[key]
318319

319320
table_pieces.append(piece)

pandas/tests/frame/test_alter_axes.py

+59
Original file line numberDiff line numberDiff line change
@@ -908,3 +908,62 @@ def test_set_reset_index(self):
908908
df = df.set_index('B')
909909

910910
df = df.reset_index()
911+
912+
def test_set_axis_inplace(self):
913+
# GH14636
914+
df = DataFrame({'A': [1.1, 2.2, 3.3],
915+
'B': [5.0, 6.1, 7.2],
916+
'C': [4.4, 5.5, 6.6]},
917+
index=[2010, 2011, 2012])
918+
919+
expected = {0: df.copy(),
920+
1: df.copy()}
921+
expected[0].index = list('abc')
922+
expected[1].columns = list('abc')
923+
expected['index'] = expected[0]
924+
expected['columns'] = expected[1]
925+
926+
for axis in expected:
927+
# inplace=True
928+
# The FutureWarning comes from the fact that we would like to have
929+
# inplace default to False some day
930+
for inplace, warn in (None, FutureWarning), (True, None):
931+
kwargs = {'inplace': inplace}
932+
933+
result = df.copy()
934+
with tm.assert_produces_warning(warn):
935+
result.set_axis(list('abc'), axis=axis, **kwargs)
936+
tm.assert_frame_equal(result, expected[axis])
937+
938+
# inplace=False
939+
result = df.set_axis(list('abc'), axis=axis, inplace=False)
940+
tm.assert_frame_equal(expected[axis], result)
941+
942+
# omitting the "axis" parameter
943+
with tm.assert_produces_warning(None):
944+
result = df.set_axis(list('abc'), inplace=False)
945+
tm.assert_frame_equal(result, expected[0])
946+
947+
# wrong values for the "axis" parameter
948+
for axis in 3, 'foo':
949+
with tm.assert_raises_regex(ValueError, 'No axis named'):
950+
df.set_axis(list('abc'), axis=axis, inplace=False)
951+
952+
def test_set_axis_prior_to_deprecation_signature(self):
953+
df = DataFrame({'A': [1.1, 2.2, 3.3],
954+
'B': [5.0, 6.1, 7.2],
955+
'C': [4.4, 5.5, 6.6]},
956+
index=[2010, 2011, 2012])
957+
958+
expected = {0: df.copy(),
959+
1: df.copy()}
960+
expected[0].index = list('abc')
961+
expected[1].columns = list('abc')
962+
expected['index'] = expected[0]
963+
expected['columns'] = expected[1]
964+
965+
# old signature
966+
for axis in expected:
967+
with tm.assert_produces_warning(FutureWarning):
968+
result = df.set_axis(axis, list('abc'), inplace=False)
969+
tm.assert_frame_equal(result, expected[axis])

pandas/tests/series/test_alter_axes.py

+44
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,47 @@ def test_rename_axis_inplace(self):
234234

235235
assert no_return is None
236236
assert_series_equal(result, expected)
237+
238+
def test_set_axis_inplace(self):
239+
# GH14636
240+
241+
s = Series(np.arange(4), index=[1, 3, 5, 7], dtype='int64')
242+
243+
expected = s.copy()
244+
expected.index = list('abcd')
245+
246+
for axis in 0, 'index':
247+
# inplace=True
248+
# The FutureWarning comes from the fact that we would like to have
249+
# inplace default to False some day
250+
for inplace, warn in (None, FutureWarning), (True, None):
251+
result = s.copy()
252+
kwargs = {'inplace': inplace}
253+
with tm.assert_produces_warning(warn):
254+
result.set_axis(list('abcd'), axis=axis, **kwargs)
255+
tm.assert_series_equal(result, expected)
256+
257+
# inplace=False
258+
result = s.set_axis(list('abcd'), axis=0, inplace=False)
259+
tm.assert_series_equal(expected, result)
260+
261+
# omitting the "axis" parameter
262+
with tm.assert_produces_warning(None):
263+
result = s.set_axis(list('abcd'), inplace=False)
264+
tm.assert_series_equal(result, expected)
265+
266+
# wrong values for the "axis" parameter
267+
for axis in 2, 'foo':
268+
with tm.assert_raises_regex(ValueError, 'No axis named'):
269+
s.set_axis(list('abcd'), axis=axis, inplace=False)
270+
271+
def test_set_axis_prior_to_deprecation_signature(self):
272+
s = Series(np.arange(4), index=[1, 3, 5, 7], dtype='int64')
273+
274+
expected = s.copy()
275+
expected.index = list('abcd')
276+
277+
for axis in 0, 'index':
278+
with tm.assert_produces_warning(FutureWarning):
279+
result = s.set_axis(0, list('abcd'), inplace=False)
280+
tm.assert_series_equal(result, expected)

0 commit comments

Comments
 (0)