Skip to content

Commit

Permalink
allow level to be passed positionally
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoGorelli committed May 17, 2021
1 parent 862addf commit 10fbed6
Show file tree
Hide file tree
Showing 10 changed files with 38 additions and 24 deletions.
2 changes: 1 addition & 1 deletion doc/source/user_guide/cookbook.rst
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ The :ref:`multindexing <advanced.hierarchical>` docs.
df.columns = pd.MultiIndex.from_tuples([tuple(c.split("_")) for c in df.columns])
df
# Now stack & Reset
df = df.stack(0).reset_index(level=1)
df = df.stack(0).reset_index(1)
df
# And fix the labels (Notice the label 'level_1' got added automatically)
df.columns = ["Sample", "All_X", "All_Y"]
Expand Down
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v1.3.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ Deprecations
- Deprecated setting :attr:`Categorical._codes`, create a new :class:`Categorical` with the desired codes instead (:issue:`40606`)
- Deprecated behavior of :meth:`DatetimeIndex.union` with mixed timezones; in a future version both will be cast to UTC instead of object dtype (:issue:`39328`)
- Deprecated using ``usecols`` with out of bounds indices for ``read_csv`` with ``engine="c"`` (:issue:`25623`)
- Deprecated passing arguments as positional in :meth:`DataFrame.reset_index` and :meth:`Series.reset_index` (:issue:`41485`)
- Deprecated passing arguments as positional (except for ``"level"``) in :meth:`DataFrame.reset_index` and :meth:`Series.reset_index` (:issue:`41485`)

.. ---------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -5568,7 +5568,7 @@ def reset_index(
) -> DataFrame | None:
...

@deprecate_nonkeyword_arguments(version="2.0", allowed_args=["self"])
@deprecate_nonkeyword_arguments(version="2.0", allowed_args=["self", "level"])
def reset_index(
self,
level: Hashable | Sequence[Hashable] | None = None,
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -1847,7 +1847,7 @@ def _drop_labels_or_levels(self, keys, axis: int = 0):
if axis == 0:
# Handle dropping index levels
if levels_to_drop:
dropped.reset_index(level=levels_to_drop, drop=True, inplace=True)
dropped.reset_index(levels_to_drop, drop=True, inplace=True)

# Handle dropping columns labels
if labels_to_drop:
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -1276,7 +1276,7 @@ def repeat(self, repeats, axis=None) -> Series:
self, method="repeat"
)

@deprecate_nonkeyword_arguments(version="2.0", allowed_args=["self"])
@deprecate_nonkeyword_arguments(version="2.0", allowed_args=["self", "level"])
def reset_index(self, level=None, drop=False, name=None, inplace=False):
"""
Generate a new DataFrame or Series with the index reset.
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/frame/methods/test_droplevel.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def test_droplevel(self, frame_or_series):
df = df.iloc[:, 0]

# test that dropping of a level in index works
expected = df.reset_index(level="a", drop=True)
expected = df.reset_index("a", drop=True)
result = df.droplevel("a", axis="index")
tm.assert_equal(result, expected)

Expand Down
24 changes: 13 additions & 11 deletions pandas/tests/frame/methods/test_reset_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,18 +142,18 @@ def test_reset_index(self, float_frame):

# only remove certain columns
df = float_frame.reset_index().set_index(["index", "A", "B"])
rs = df.reset_index(level=["A", "B"])
rs = df.reset_index(["A", "B"])

# TODO should reset_index check_names ?
tm.assert_frame_equal(rs, float_frame, check_names=False)

rs = df.reset_index(level=["index", "A", "B"])
rs = df.reset_index(["index", "A", "B"])
tm.assert_frame_equal(rs, float_frame.reset_index(), check_names=False)

rs = df.reset_index(level=["index", "A", "B"])
rs = df.reset_index(["index", "A", "B"])
tm.assert_frame_equal(rs, float_frame.reset_index(), check_names=False)

rs = df.reset_index(level="A")
rs = df.reset_index("A")
xp = float_frame.reset_index().set_index(["index", "B"])
tm.assert_frame_equal(rs, xp, check_names=False)

Expand All @@ -165,7 +165,7 @@ def test_reset_index(self, float_frame):
tm.assert_frame_equal(df, reset, check_names=False)

df = float_frame.reset_index().set_index(["index", "A", "B"])
rs = df.reset_index(level="A", drop=True)
rs = df.reset_index("A", drop=True)
xp = float_frame.copy()
del xp["A"]
xp = xp.set_index(["B"], append=True)
Expand Down Expand Up @@ -262,23 +262,23 @@ def test_reset_index_multiindex_col(self):
MultiIndex.from_arrays([[0, 1, 2], ["x", "y", "z"]], names=["d", "a"]),
columns=[["b", "b", "c"], ["mean", "median", "mean"]],
)
rs = df.reset_index(level="a")
rs = df.reset_index("a")
xp = DataFrame(
full,
Index([0, 1, 2], name="d"),
columns=[["a", "b", "b", "c"], ["", "mean", "median", "mean"]],
)
tm.assert_frame_equal(rs, xp)

rs = df.reset_index(level="a", col_fill=None)
rs = df.reset_index("a", col_fill=None)
xp = DataFrame(
full,
Index(range(3), name="d"),
columns=[["a", "b", "b", "c"], ["a", "mean", "median", "mean"]],
)
tm.assert_frame_equal(rs, xp)

rs = df.reset_index(level="a", col_fill="blah", col_level=1)
rs = df.reset_index("a", col_fill="blah", col_level=1)
xp = DataFrame(
full,
Index(range(3), name="d"),
Expand Down Expand Up @@ -665,7 +665,7 @@ def test_reset_index_multiindex_nat():
tstamp = date_range("2015-07-01", freq="D", periods=3)
df = DataFrame({"id": idx, "tstamp": tstamp, "a": list("abc")})
df.loc[2, "tstamp"] = pd.NaT
result = df.set_index(["id", "tstamp"]).reset_index(level="id")
result = df.set_index(["id", "tstamp"]).reset_index("id")
expected = DataFrame(
{"id": range(3), "a": list("abc")},
index=pd.DatetimeIndex(["2015-07-01", "2015-07-02", "NaT"], name="tstamp"),
Expand All @@ -678,7 +678,9 @@ def test_drop_pos_args_deprecation():
df = DataFrame({"a": [1, 2, 3]}).set_index("a")
msg = (
r"Starting with Pandas version 2\.0 all arguments of reset_index except for "
r"the argument 'self' will be keyword-only"
r"the arguments 'self' and 'level' will be keyword-only"
)
with tm.assert_produces_warning(FutureWarning, match=msg):
df.reset_index("a")
result = df.reset_index("a", False)
expected = DataFrame({"a": [1, 2, 3]})
tm.assert_frame_equal(result, expected)
2 changes: 1 addition & 1 deletion pandas/tests/groupby/test_grouping.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ def test_grouper_column_and_index(self):

# Grouping a single-index frame by a column and the index should
# be equivalent to resetting the index and grouping by two columns
df_single = df_multi.reset_index(level="outer")
df_single = df_multi.reset_index("outer")
result = df_single.groupby(["B", pd.Grouper(level="inner")]).mean()
expected = df_single.reset_index().groupby(["B", "inner"]).mean()
tm.assert_frame_equal(result, expected)
Expand Down
4 changes: 2 additions & 2 deletions pandas/tests/reshape/merge/test_merge_index_as_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ def compute_expected(df_left, df_right, on=None, left_on=None, right_on=None, ho
# Drop index levels that aren't involved in the merge
drop_left = [n for n in left_levels if n not in left_on]
if drop_left:
df_left = df_left.reset_index(level=drop_left, drop=True)
df_left = df_left.reset_index(drop_left, drop=True)

drop_right = [n for n in right_levels if n not in right_on]
if drop_right:
df_right = df_right.reset_index(level=drop_right, drop=True)
df_right = df_right.reset_index(drop_right, drop=True)

# Convert remaining index levels to columns
reset_left = [n for n in left_levels if n in left_on]
Expand Down
20 changes: 16 additions & 4 deletions pandas/tests/series/methods/test_reset_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def test_reset_index_level(self):
s.reset_index(level=[0, 1, 2])

# Check that .reset_index([],drop=True) doesn't fail
result = Series(range(4)).reset_index(level=[], drop=True)
result = Series(range(4)).reset_index([], drop=True)
expected = Series(range(4))
tm.assert_series_equal(result, expected)

Expand All @@ -127,14 +127,14 @@ def test_reset_index_drop_errors(self):
# KeyError raised for series index when passed level name is missing
s = Series(range(4))
with pytest.raises(KeyError, match="does not match index name"):
s.reset_index(level="wrong", drop=True)
s.reset_index("wrong", drop=True)
with pytest.raises(KeyError, match="does not match index name"):
s.reset_index(level="wrong")
s.reset_index("wrong")

# KeyError raised for series when level to be dropped is missing
s = Series(range(4), index=MultiIndex.from_product([[1, 2]] * 2))
with pytest.raises(KeyError, match="not found"):
s.reset_index(level="wrong", drop=True)
s.reset_index("wrong", drop=True)

def test_reset_index_with_drop(self, series_with_multilevel_index):
ser = series_with_multilevel_index
Expand All @@ -148,6 +148,18 @@ def test_reset_index_with_drop(self, series_with_multilevel_index):
assert isinstance(deleveled, Series)
assert deleveled.index.name == ser.index.name

def test_drop_pos_args_deprecation(self):
# https://github.com/pandas-dev/pandas/issues/41485
ser = Series([1, 2, 3], index=Index([1, 2, 3], name="a"))
msg = (
r"Starting with Pandas version 2\.0 all arguments of reset_index except "
r"for the arguments 'self' and 'level' will be keyword-only"
)
with tm.assert_produces_warning(FutureWarning, match=msg):
result = ser.reset_index("a", False)
expected = DataFrame({"a": [1, 2, 3], 0: [1, 2, 3]})
tm.assert_frame_equal(result, expected)


@pytest.mark.parametrize(
"array, dtype",
Expand Down

0 comments on commit 10fbed6

Please sign in to comment.