【问题标题】:Flatten DataFrame with multi-index columns使用多索引列展平 DataFrame
【发布时间】:2019-06-18 06:50:36
【问题描述】:

我想将派生自数据透视表的 Pandas DataFrame 转换为如下所示的行表示形式。

这就是我所在的地方:

import pandas as pd
import numpy as np
df = pd.DataFrame({
    'goods': ['a', 'a', 'b', 'b', 'b'],
    'stock': [5, 10, 30, 40, 10],
    'category': ['c1', 'c2', 'c1', 'c2', 'c1'],
    'date': pd.to_datetime(['2014-01-01', '2014-02-01', '2014-01-06', '2014-02-09', '2014-03-09'])
})
# we don't care about year in this example
df['month'] = df['date'].map(lambda x: x.month)
piv = df.pivot_table(["stock"], "month", ["goods", "category"], aggfunc="sum")
piv = piv.reindex(np.arange(piv.index[0], piv.index[-1] + 1))
piv = piv.ffill(axis=0)
piv = piv.fillna(0)
print piv

导致

stock            
goods        a       b    
category    c1  c2  c1  c2
month                     
1            5   0  30   0
2            5  10  30  40
3            5  10  10  40

这就是我想去的地方。

goods category month stock
    a       c1     1     5
    a       c1     2     0
    a       c1     3     0
    a       c2     1     0
    a       c2     2    10
    a       c2     3     0
    b       c1     1    30
    b       c1     2     0
    b       c1     3    10
    b       c2     1     0
    b       c2     2    40
    b       c2     3     0

Previously,我用过

piv = piv.stack()
piv = piv.reset_index()
print piv

摆脱多索引,但这会导致这种情况,因为我现在在两列上进行旋转 (["goods", "category"]):

      month category stock    
goods                    a   b
0         1       c1     5  30
1         1       c2     0   0
2         2       c1     5  30
3         2       c2    10  40
4         3       c1     5  10
5         3       c2    10  40

有谁知道我如何摆脱列中的多索引并将结果放入示例格式的 DataFrame 中?

【问题讨论】:

    标签: python pandas pivot-table


    【解决方案1】:
    >>> piv.unstack().reset_index().drop('level_0', axis=1)
       goods category  month   0
    0      a       c1      1   5
    1      a       c1      2   5
    2      a       c1      3   5
    3      a       c2      1   0
    4      a       c2      2  10
    5      a       c2      3  10
    6      b       c1      1  30
    7      b       c1      2  30
    8      b       c1      3  10
    9      b       c2      1   0
    10     b       c2      2  40
    11     b       c2      3  40
    

    那么您只需将最后一列名称从0 更改为stock

    【讨论】:

    • hmmmm,融化(我的回答)从索引中损失了一个月:(
    • 谢谢。它适用于我的示例。但是,我不太明白为什么以前使用 stack 有效,而我现在应该使用 unstack
    【解决方案2】:

    在我看来melt (aka unpivot) 非常接近你想要做的事情:

    In [11]: pd.melt(piv)
    Out[11]:
          NaN goods category  value
    0   stock     a       c1      5
    1   stock     a       c1      5
    2   stock     a       c1      5
    3   stock     a       c2      0
    4   stock     a       c2     10
    5   stock     a       c2     10
    6   stock     b       c1     30
    7   stock     b       c1     30
    8   stock     b       c1     10
    9   stock     b       c2      0
    10  stock     b       c2     40
    11  stock     b       c2     40
    

    有一个流氓列(股票),出现在这里,列标题在 piv 中是恒定的。如果我们先放下它,融化就可以了 OOTB:

    In [12]: piv.columns = piv.columns.droplevel(0)
    
    In [13]: pd.melt(piv)
    Out[13]:
       goods category  value
    0      a       c1      5
    1      a       c1      5
    2      a       c1      5
    3      a       c2      0
    4      a       c2     10
    5      a       c2     10
    6      b       c1     30
    7      b       c1     30
    8      b       c1     10
    9      b       c2      0
    10     b       c2     40
    11     b       c2     40
    

    编辑:上面实际上删除了索引,您需要将其设为带有reset_index的列:

    In [21]: pd.melt(piv.reset_index(), id_vars=['month'], value_name='stock')
    Out[21]:
        month goods category  stock
    0       1     a       c1      5
    1       2     a       c1      5
    2       3     a       c1      5
    3       1     a       c2      0
    4       2     a       c2     10
    5       3     a       c2     10
    6       1     b       c1     30
    7       2     b       c1     30
    8       3     b       c1     10
    9       1     b       c2      0
    10      2     b       c2     40
    11      3     b       c2     40
    

    【讨论】:

    • 有趣的函数,但是“月”列去哪儿了?
    • @orange 索引似乎已被删除,将这个答案留在这里,因为它可能对某些人有用(我也希望我能修复它!)。
    • 您认为这是一个错误还是设计使然?
    • @orange 我不会说这是一个错误,但可能是一个功能/增强功能(不删除索引)。此外,您不能传递像 col_level=[1, 2] 这样有用的东西。
    • 谢谢。我会留意这个功能,以备日后使用。
    【解决方案3】:

    我知道问题已经得到解答,但是对于我的数据集多索引列问题,提供的解决方案效率低下。因此,我在这里发布了另一个使用 pandas 取消透视多索引列的解决方案。

    这是我遇到的问题:

    可以看出,dataframe 由 3 个多索引和两级多索引列组成。

    所需的数据帧格式是:

    当我尝试上面给出的选项时,pd.melt 函数不允许在 var_name 属性中包含多于一列。因此,每次我尝试融化时,我都会从表中丢失一些属性。

    我找到的解决方案是在我的数据框上应用双堆叠功能。

    在编码之前,值得注意的是,我的未透视表列所需的 var_name 是“Populacao residente em domicilios specifices ocupados”(参见下面的代码)。因此,对于我所有的值条目,它们应该堆叠在这个新创建的 var_name 新列中。

    这是一个sn-p代码:

    import pandas as pd
    
    # reading my table
    
    df = pd.read_excel(r'my_table.xls', sep=',', header=[2,3], encoding='latin3', 
                   index_col=[0,1,2], na_values=['-', ' ', '*'], squeeze=True).fillna(0)
    
    df.index.names = ['COD_MUNIC_7', 'NOME_MUN', 'TIPO']
    df.columns.names = ['sexo', 'faixa_etaria']
    
    
    df.head()
    
    
    # making the stacking:
    
    df = pd.DataFrame(pd.Series(df.stack(level=0).stack(), name='Populacao residente em domicilios particulares ocupados')).reset_index()
    
    
    df.head()
    

    我发现的另一个解决方案是首先在数据帧上应用堆叠功能,然后应用熔化。

    这是一个替代代码:

    df = df.stack('faixa_etaria').reset_index().melt(id_vars=['COD_MUNIC_7', 'NOME_MUN','TIPO', 'faixa_etaria'],
                      value_vars=['Homens', 'Mulheres'],
                      value_name='Populacao residente em domicilios particulares ocupados', 
                      var_name='sexo')
    
    df.head()
    

    此致,

    菲利普·里斯卡拉·利尔

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-06
      • 2021-05-07
      • 1970-01-01
      • 1970-01-01
      • 2019-06-29
      • 1970-01-01
      • 1970-01-01
      • 2012-01-19
      相关资源
      最近更新 更多