pandas' "pivot" 操作的精确逆运算

Exact inverse of pandas' "pivot" operation

我有一个 pandas 粗略格式的数据框

print(df)
    Time  GroupA  GroupB  Value1  Value2
0  100.0     1.0     1.0    18.0     0.0
1  100.0     1.0     2.0    16.0     0.0
2  100.0     2.0     1.0    18.0     0.0
3  100.0     2.0     2.0    10.0     0.0

其中Time是计数变量/时间戳,GroupAGroupB是类别,Value1Value2是数值量。此代码片段创建了一个模型数据框:

import numpy as np
values = np.zeros(shape=(4,5))
values[:,0] = 100
values[:,1] = [1]*2 + [2]*2
values[:,2] = [1,2]*2
values[:,3] = np.random.randint(low=10,high=20,size=(4))
df = pd.DataFrame(values,columns=['Time','GroupA','GroupB','Value1','Value2'])

加载一些数据后,我想计算并填写Value2的值。碰巧的是(因为,顺便说一下,Value2 是每个现有 (GroupAGroupB) 对中 Value1 的时间序列函数),我发现最容易计算这些首先将我的数据转换为以下形式的值:

df_pivot = df.pivot_table(index='Time',columns=['GroupA','GroupB'],values=['Value1','Value2'], fill_value=0.0)

然后在一些不相关的代码之后我填写了值

print(df_pivot)
       Value1             Value2            
GroupA    1.0     2.0        1.0     2.0    
GroupB    1.0 2.0 1.0 2.0    1.0 2.0 1.0 2.0
Time                                        
100.0      13  16  16  10     27  20  28  20

现在我想"unpivot"把它恢复成df原来的格式。我可以通过遍历 df、查找 df_pivot 中的值并填充它来手动执行此操作,但我更愿意使用内置函数。尝试使用 df.melt 的变体,我无法执行此反转,因为 df_pivot 的分层列存在问题。我最好的尝试是

dfm = df_pivot.reset_index().melt(id_vars="Time")
dfm.columns.values[1] = "HACK"
dfm = dfm.pivot_table(index=["Time","GroupA","GroupB"],columns="HACK",values="value").reset_index()

生成数据框

print(dfm)
HACK   Time  GroupA  GroupB  Value1  Value2
0     100.0     1.0     1.0      13      27
1     100.0     1.0     2.0      16      20
2     100.0     2.0     1.0      16      28
3     100.0     2.0     2.0      10      20

这行得通,但我觉得这不是最佳解决方案,也不是非常便携(为什么 melt 会生成 "NaN" 列名?为什么我要手动查找此列的索引并重命名它?为什么我必须要撤消枢轴?)尝试并查看文档和示例以寻找替代方案,但我不知所措。 melt 函数有一个 col_level 参数,看起来应该有帮助,但我为此使用的任何有效值只会导致数据丢失(丢失 "Time"、"GroupA"、或 "GroupB" 数据)。

我觉得stack比较直白

df_pivot.stack([1,2]).reset_index()
Out[8]: 
    Time  GroupA  GroupB  Value1  Value2
0  100.0     1.0     1.0      13       0
1  100.0     1.0     2.0      13       0
2  100.0     2.0     1.0      12       0
3  100.0     2.0     2.0      11       0