-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
BUG: Let melt
name multiple variable columns for labels from a MultiIndex
#58088
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
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,9 +64,10 @@ def melt( | |
value_vars : scalar, tuple, list, or ndarray, optional | ||
Column(s) to unpivot. If not specified, uses all columns that | ||
are not set as `id_vars`. | ||
var_name : scalar, default None | ||
var_name : scalar, tuple, list, or ndarray, optional | ||
Name to use for the 'variable' column. If None it uses | ||
``frame.columns.name`` or 'variable'. | ||
``frame.columns.name`` or 'variable'. Must be a scalar if columns are a | ||
MultiIndex. | ||
value_name : scalar, default 'value' | ||
Name to use for the 'value' column, can't be an existing column label. | ||
col_level : scalar, optional | ||
|
@@ -217,7 +218,15 @@ def melt( | |
frame.columns.name if frame.columns.name is not None else "variable" | ||
] | ||
elif is_list_like(var_name): | ||
raise ValueError(f"{var_name=} must be a scalar.") | ||
if isinstance(frame.columns, MultiIndex): | ||
var_name = list(var_name) | ||
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. Is the 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.
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. Ah true. Could you use |
||
if len(var_name) > len(frame.columns): | ||
raise ValueError( | ||
f"{var_name=} has {len(var_name)} items, " | ||
f"but the dataframe columns only have {len(frame.columns)} levels." | ||
) | ||
else: | ||
raise ValueError(f"{var_name=} must be a scalar.") | ||
else: | ||
var_name = [var_name] | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -533,6 +533,22 @@ def test_melt_non_scalar_var_name_raises(self): | |
with pytest.raises(ValueError, match=r".* must be a scalar."): | ||
df.melt(id_vars=["a"], var_name=[1, 2]) | ||
|
||
def test_melt_multiindex_columns_var_name(self): | ||
# GH 58033 | ||
df = DataFrame({("A", "a"): [1], ("A", "b"): [2]}) | ||
|
||
expected = DataFrame( | ||
[("A", "a", 1), ("A", "b", 2)], columns=["first", "second", "value"] | ||
) | ||
|
||
tm.assert_frame_equal(df.melt(var_name=["first", "second"]), expected) | ||
tm.assert_frame_equal(df.melt(var_name=["first"]), expected[["first", "value"]]) | ||
|
||
with pytest.raises( | ||
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. Could you make this a separate test? |
||
ValueError, match="but the dataframe columns only have 2 levels" | ||
): | ||
df.melt(var_name=["first", "second", "third"]) | ||
|
||
|
||
class TestLreshape: | ||
def test_pairs(self): | ||
|
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.
Could you move this to
v3.0.0rst
?