如何在使用 Pandas 的透视表后取消多级索引?

48

我有以下数据框(真实数据框比这个大得多):

sale_user_id    sale_product_id count
1                 1              1
1                 8              1
1                 52             1
1                 312            5
1                 315            1

然后使用以下代码将sale_product_id中的值重新塑造为列标题:

reshaped_df=id_product_count.pivot(index='sale_user_id',columns='sale_product_id',values='count')

而结果数据帧为:

sale_product_id -1057   1   2   3   4   5   6   8   9   10  ... 98  980 981 982 983 984 985 986 987 99
sale_user_id                                                                                    
1                NaN    1.0 NaN NaN NaN NaN NaN 1.0 NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3                NaN    1.0 NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4                NaN    NaN 1.0 NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

正如您所看到的,我们有一个多层级索引,我需要的是将 sale_user_is 放在第一列而不是多层级索引:

我采取以下方法:

reshaped_df.reset_index()

结果将会是这样,我仍然拥有 sale_product_id 列,但我不再需要它:

sale_product_id sale_user_id    -1057   1   2   3   4   5   6   8   9   ... 98  980 981 982 983 984 985 986 987 99
0                          1    NaN 1.0 NaN NaN NaN NaN NaN 1.0 NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1                          3    NaN 1.0 NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2                          4    NaN NaN 1.0 NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN 

我可以对这个数据框进行子集操作,以摆脱sale_product_id,但我认为这样并不高效。我正在寻找一种有效的方法,在重塑原始数据框时摆脱多级索引。


截至2020年,解决方案可能是使用 reshaped_df.droplevel(1, axis=0) (文档),但我不确定我完全理解所选答案解决的问题。 - mins
6个回答

46

您只需要删除 索引名称,并使用 rename_axis(在 pandas 0.18.0 中新增):

print (reshaped_df)
sale_product_id  1    8    52   312  315
sale_user_id                            
1                  1    1    1    5    1

print (reshaped_df.index.name)
sale_user_id

print (reshaped_df.rename_axis(None))
sale_product_id  1    8    52   312  315
1                  1    1    1    5    1

另一个在 pandas 版本低于 0.18.0 的解决方案如下:

reshaped_df.index.name = None
print (reshaped_df)

sale_product_id  1    8    52   312  315
1                  1    1    1    5    1
如果需要删除列名: columns name
print (reshaped_df.columns.name)
sale_product_id

print (reshaped_df.rename_axis(None).rename_axis(None, axis=1))
   1    8    52   312  315
1    1    1    1    5    1

另一个解决方案:

reshaped_df.columns.name = None
reshaped_df.index.name = None
print (reshaped_df)
   1    8    52   312  315
1    1    1    1    5    1

根据评论编辑:

您需要使用带有参数drop=Truereset_index

reshaped_df = reshaped_df.reset_index(drop=True)
print (reshaped_df)
sale_product_id  1    8    52   312  315
0                  1    1    1    5    1

#if need reset index nad remove column name
reshaped_df = reshaped_df.reset_index(drop=True).rename_axis(None, axis=1)
print (reshaped_df)
   1    8    52   312  315
0    1    1    1    5    1

如果只需要删除列名:

reshaped_df = reshaped_df.rename_axis(None, axis=1)
print (reshaped_df)
              1    8    52   312  315
sale_user_id                         
1               1    1    1    5    1

编辑1:

如果需要从index创建新的列并删除列名

reshaped_df =  reshaped_df.rename_axis(None, axis=1).reset_index() 
print (reshaped_df)
   sale_user_id  1  8  52  312  315
0             1  1  1   1    5    1

我尝试了所有的解决方案,实际上前两个解决方案都删除了sale_user_id,但我需要它作为第一列,我需要摆脱sale_product_id。 - chessosapiens
最后两个解决方案也会删除sale_user_id。 - chessosapiens
2
我认为我们需要添加reset_index(),reshaped_df.rename_axis(None, axis=1).reset_index()将会给我我所需要的东西。 - chessosapiens

9

创建一个数据框

import random

d = {'Country': ['Afghanistan','Albania','Algeria','Andorra','Angola']*2, 
     'Year': [2005]*5 + [2006]*5, 'Value': random.sample(range(1,20),10)}
df = pd.DataFrame(data=d)

df:

                Country         Year   Value    
1               Afghanistan     2005    6
2               Albania         2005    13
3               Algeria         2005    10
4               Andorra         2005    11
5               Angola          2005    5
6               Afghanistan     2006    3
7               Albania         2006    2
8               Algeria         2006    7
9               Andorra         2006    3
10              Angola          2006    6

数据透视表
table = df.pivot(index='Country',columns='Year',values='Value')

表格:

Year    Country         2005    2006
0       Afghanistan     16      9
1       Albania         17      19
2       Algeria         11      7
3       Andorra         5       12
4       Angola          6       18

我希望将“年份”改为“索引”:

clean_tbl = table.rename_axis(None, axis=1).reset_index(drop=True)

清空_tbl:

    Country         2005    2006
0   Afghanistan     16      9
1   Albania         17      19
2   Algeria         11      7
3   Andorra         5       12
4   Angola          6       18

翻译完成!


4

你也可以使用MultiIndex对象的to_flat_index方法将其转换为元组列表,然后通过列表推导式连接并将其用于覆盖数据框的.columns属性。

# create a dataframe
df = pd.DataFrame({"a": [1, 2, 3, 1], "b": ["x", "x", "y", "y"], "c": [0.1, 0.2, 0.1, 0.2]})


    a   b   c
0   1   x   0.1
1   2   x   0.2
2   3   y   0.1
3   1   y   0.2

# pivot the dataframe
df_pivoted = df.pivot(index="a", columns="b")

    c
b   x   y
a       
1   0.1 0.2
2   0.2 NaN
3   NaN 0.1

现在让我们覆盖 .columns 属性和 .reset_index() 方法:
df_pivoted.columns = ["_".join(tup) for tup in df_pivoted.columns.to_flat_index()]
df_pivoted.reset_index()

    a   c_x c_y
0   1   0.1 0.2
1   2   0.2 NaN
2   3   NaN 0.1

2
我们需要使用reset_index()将索引列重置回数据框,然后使用rename_axis()将索引重命名为None,并将列重命名为它们的axis=1(列标题)值。
reshaped_df = reshaped_df.reset_index().rename_axis(None, axis=1)

0
使用 pivot 将长格式转换为宽格式:
import pandas
df = pandas.DataFrame({
    "lev1": [1, 1, 1, 2, 2, 2],
    "lev2": [1, 1, 2, 1, 1, 2],
    "lev3": [1, 2, 1, 2, 1, 2],
    "lev4": [1, 2, 3, 4, 5, 6],
    "values": [0, 1, 2, 3, 4, 5]})
df_wide = df.pivot(index="lev1", columns=["lev2", "lev3"], values="values")
df_wide

# lev2    1         2
# lev3    1    2    1    2
# lev1
# 1     0.0  1.0  2.0  NaN
# 2     4.0  3.0  NaN  5.0

重命名(有时令人困惑的)轴名称

df_wide.rename_axis(columns=[None, None])

#         1         2
#         1    2    1    2
# lev1
# 1     0.0  1.0  2.0  NaN
# 2     4.0  3.0  NaN  5.0

-1

对我来说,它的工作方式是

df_cross=pd.DataFrame(pd.crosstab(df[c1], df[c2]).to_dict()).reset_index()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接