diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 5200ad0ba0d23..4946ce4e13eae 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -6312,6 +6312,10 @@ def unstack(self, level=-1, fill_value=None): Name to use for the 'value' column. col_level : int or str, optional If columns are a MultiIndex then use this level to melt. + keep_index : boolean, optional, default False + If True, the original index is reused. + In the resulting MulitIndex the names of the unpivoted columns + are added as an additional level to ensure uniqueness. Returns ------- @@ -6396,6 +6400,7 @@ def melt( var_name=None, value_name="value", col_level=None, + keep_index=False, ): from pandas.core.reshape.melt import melt @@ -6406,6 +6411,7 @@ def melt( var_name=var_name, value_name=value_name, col_level=col_level, + keep_index=keep_index, ) # ---------------------------------------------------------------------- diff --git a/pandas/core/reshape/melt.py b/pandas/core/reshape/melt.py index 6f2e264f1a4d0..c01f15f2682bd 100644 --- a/pandas/core/reshape/melt.py +++ b/pandas/core/reshape/melt.py @@ -27,6 +27,7 @@ def melt( var_name=None, value_name="value", col_level=None, + keep_index=False, ): # TODO: what about the existing index? # If multiindex, gather names of columns on all level for checking presence @@ -116,7 +117,23 @@ def melt( # asanyarray will keep the columns as an Index mdata[col] = np.asanyarray(frame.columns._get_level_values(i)).repeat(N) - return frame._constructor(mdata, columns=mcolumns) + result = frame._constructor(mdata, columns=mcolumns) + + if keep_index: + orig_index_values = list(np.tile(frame.index.get_values(), K)) + + if len(frame.index.names) == len(set(frame.index.names)): + orig_index_names = frame.index.names + else: + orig_index_names = [ + "original_index_{i}".format(i=i) for i in range(len(frame.index.names)) + ] + + result[orig_index_names] = frame._constructor(orig_index_values) + + result = result.set_index(orig_index_names + list(var_name)) + + return result def lreshape(data, groups, dropna=True, label=None):