首页 > 解决方案 > 取消堆叠具有重复项的多索引

问题描述

我有一个看起来像这样的数据框

Date     ID   Value
Mar-20   A     100
Mar-20   B     200
Mar-20   C     300
Apr-20   A     101
Apr-20   B     201
Apr-20   C     301

我正在尝试重新塑造它,使其看起来像这样

        Value
ID       A      B      c
Date
Mar-20  100    200    300
Apr-20  101    201    301

我开始尝试

df = df.set_index(["Date", "ID"])

但是将其拆分为以下值错误:“索引包含重复的条目,无法重塑”所以我在 SO 上找到了这个建议,这让我可以拆分

df = df.set_index(["Date", "ID"].append = True)

但是当我通过“ID”(即 df = df.unstack("ID") 取消堆叠时,我的最终数据框看起来像这样

         Value 
Date     ID     A    B    C
Mar-20   A     100  NaN  NaN
Mar-20   B     NaN  200  NaN
Mar-20   C     NaN  NaN  300
Apr-20   A     101  NaN  NaN 
Apr-20   B     NaN  201  NaN 
Apr-20   C     NaN  NaN  301

如何压缩它以获得我想要的输出?

非常感谢

标签: pandas

解决方案


用于DataFrame.unstack预期输出(索引顺序已更改):

df = df.set_index(["Date", "ID"]).unstack()
print (df)
       Value          
ID         A    B    C
Date                  
Apr-20   101  201  301
Mar-20   100  200  300

对于正确的顺序是可能的添加to_datetime

df['Date'] = pd.to_datetime(df['Date'], format='%b-%y')
df = df.set_index(["Date", "ID"]).unstack()
print (df)
           Value          
ID             A    B    C
Date                      
2020-03-01   100  200  300
2020-04-01   101  201  301

如果需要正确顺序的原始格式:

df['Date'] = pd.to_datetime(df['Date'], format='%b-%y')
df = df.set_index(["Date", "ID"]).unstack().rename(lambda x: x.strftime('%b-%y'))
print (df)
       Value          
ID         A    B    C
Date                  
Mar-20   100  200  300
Apr-20   101  201  301

如果只有 3 列是可能的使用DataFrame.pivot,但如果更多的列失败,所以如果一般数据不要使用它:

df['Date'] = pd.to_datetime(df['Date'], format='%b-%y')
df = df.pivot(*df.columns).rename(lambda x: x.strftime('%b-%y'))
print (df)
ID        A    B    C
Date                 
Mar-20  100  200  300
Apr-20  101  201  301

如果输入数据中有任何列并且只需要旋转大约 3 列,则最好使用:

df['Date'] = pd.to_datetime(df['Date'], format='%b-%y')
df = df.pivot('Date','ID','Value').rename(lambda x: x.strftime('%b-%y'))
print (df)
ID        A    B    C
Date                 
Mar-20  100  200  300
Apr-20  101  201  301

编辑:如果得到错误:

索引包含重复条目,无法重新整形

这意味着每对有重复项,因此有Date, ID必要使用聚合函数,sum例如:meanDataFrame.pivot_table

print (df)
     Date ID  Value
0  Mar-20  A    100 <- same Date, ID
1  Mar-20  A    500 <- same Date, ID
2  Mar-20  B    200
3  Mar-20  C    300
4  Apr-20  A    101
5  Apr-20  B    201
6  Apr-20  C    301



df['Date'] = pd.to_datetime(df['Date'], format='%b-%y')
df = df.pivot_table(index='Date',
                    columns='ID',
                    values='Value',
                    aggfunc='sum').rename(lambda x: x.strftime('%b-%y'))
print (df)
ID        A    B    C
Date                 
Mar-20  600  200  300 < aggregate sum 100+500=600
Apr-20  101  201  301

如果需要使用ValueMultiIndex

df['Date'] = pd.to_datetime(df['Date'], format='%b-%y')
df = df.pivot_table(index='Date',
                    columns='ID',
                    values=['Value'], 
                    aggfunc='sum').rename(lambda x: x.strftime('%b-%y'))
print (df)
       Value          
ID         A    B    C
Date                  
Mar-20   600  200  300
Apr-20   101  201  301

如果需要避免排序,更好的解决方案,谢谢@anky:

df = df.groupby(["Date", "ID"],sort=False)['Value'].sum().unstack()
print (df)
ID        A    B    C
Date                 
Mar-20  600  200  300
Apr-20  101  201  301

推荐阅读