取消堆叠具有重复项的多索引

Posted

技术标签:

【中文标题】取消堆叠具有重复项的多索引【英文标题】:Unstacking a multi-index with duplicates 【发布时间】:2020-09-22 06:32:42 【问题描述】:

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

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"])

但是将这个 let 取消堆叠到以下值错误:“索引包含重复的条目,无法重塑” 所以我在 SO 上找到了这个建议,这让我可以 unstack

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

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

非常感谢

【问题讨论】:

@YOBEN_S - 是的,你支持 75% 正确,不幸的是,这个日期时间有点复杂。 @jezrael df.pivot(*df.columns)? @YOBEN_S - 好点,添加到答案中。 @jezrael 将重新打开呵呵 【参考方案1】:

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,所以必须使用聚合函数,如DataFrame.pivot_table中的summean

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

如果需要在MultiIndex 中使用列Value

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

【讨论】:

非常感谢您回到我身边。当我尝试第一个版本时,我收到“索引包含重复条目,无法重新整形”的值错误。当我将 append = True 添加到 set_index 时,我会得到不同版本的索引的负载(每个 ID 1 个) @harrison10001 - 检查最后一段以获得解决方案。 非常感谢。我会试一试 @anky - 谢谢。

以上是关于取消堆叠具有重复项的多索引的主要内容,如果未能解决你的问题,请参考以下文章

具有重复值的 Python 多索引切片

重命名具有任意顺序和重复列名的多索引列

在熊猫多索引数据框中返回满足逻辑索引条件的每个组的最后一行[重复]

Pandas:根据多索引系列更改重复项

重命名多索引数据框熊猫[重复]

来自多索引数据的堆叠图