翼度科技»论坛 编程开发 python 查看内容

Pandas.Groupby之后的多层级索引

4

主题

4

帖子

12

积分

新手上路

Rank: 1

积分
12
Pandas多级层索引

官方一点的说法:Pandas中的多级索引(MultiIndex)是一种允许在单个轴上拥有多个索引级别的索引对象。这种索引结构在处理具有复杂层次结构的数据时非常有用,因为它能够提供更丰富的数据访问和操作能力。


我自己的理解是在excel表格中一个大类里面还有其他子类,子类存储数据。
今天出这样一个notebook主要是想到之前在使用pandas中的groupby传递多列作为一个唯一分组时会返回一个多级索引的dataframe,
那时并不会看也不知道该怎么操作,就只会用transform()函数运算。最后算完了只要一组数据后还得去重哈哈哈哈。所以现在出一篇可能会给大家有点参考顺带给自己巩固一下。


多层级索引的概念

多层级索引(MultiIndex)是Pandas库中一种非常重要的数据结构,它允许在DataFrame或Series的轴(行或列)上拥有多个(两个以上)索引级别。这种结构能够增强数据集的维度管理,便于组织复杂结构数据,为数据集增加更多的维度,使得我们能够更好地组织和表示具有复杂结构的数据。
模块导入
  1. import pandas as pd
  2. import numpy as np
  3. from random import choice
复制代码
使用groupby和agg返回的多层索引dataframe

创建一个基础dataframe

创建的dataframe内容有三列分别是:产品、月份、数量
  1. # 创建组成dataframe的数据
  2. values = np.random.randint(1,50,size=12)
  3. month = ['一月','二月','三月']
  4. product = ['A','B']
  5. temp_1,temp_2 = [] , []
  6. for i in range(0,12):
  7.     temp_1.append(choice(month))
  8.     temp_2.append(choice(product))
  9. data = [temp_1,temp_2,values]
  10. data_transposed = [list(x) for x in zip(*data)]
  11. data_transposed
复制代码
  1. [['三月', 'B', np.int32(23)],
  2. ['一月', 'B', np.int32(26)],
  3. ['二月', 'A', np.int32(48)],
  4. ['三月', 'B', np.int32(3)],
  5. ['一月', 'B', np.int32(25)],
  6. ['二月', 'A', np.int32(20)],
  7. ['三月', 'A', np.int32(14)],
  8. ['二月', 'A', np.int32(25)],
  9. ['一月', 'A', np.int32(21)],
  10. ['三月', 'A', np.int32(14)],
  11. ['二月', 'A', np.int32(46)],
  12. ['二月', 'B', np.int32(23)]]
复制代码
  1. # 构建dataframe
  2. df = pd.DataFrame(data=data_transposed,columns=['月份','产品','数量'])
  3. df , df.index
复制代码
  1. (    月份 产品  数量
  2. 0   三月  B  23
  3. 1   一月  B  26
  4. 2   二月  A  48
  5. 3   三月  B   3
  6. 4   一月  B  25
  7. 5   二月  A  20
  8. 6   三月  A  14
  9. 7   二月  A  25
  10. 8   一月  A  21
  11. 9   三月  A  14
  12. 10  二月  A  46
  13. 11  二月  B  23,
  14. RangeIndex(start=0, stop=12, step=1))
复制代码
上面这个dataframe就是模拟了一下平时做数据的时候可能会读取到这种样式的数据,但这样看密密麻麻不美观也不容易看出每个产品每月的总数量。那就使用groupby来进行分组再聚合运算
  1. # 分组聚合运算返回新的dataframe或series
  2. df_group = df.groupby(['产品','月份'])['数量'].agg('sum')
  3. df_group
复制代码
  1. 产品  月份
  2. A   一月     21
  3.     三月     28
  4.     二月    139
  5. B   一月     51
  6.     三月     26
  7.     二月     23
  8. Name: 数量, dtype: int32
复制代码
这里因为分组已经拿走了两列作为唯一值索引,剩下数量这一列数据所以返回的是一个多层级索引的series,可以使用pd.dataframe转换
  1. df_group = pd.DataFrame(df_group)
  2. df_group
复制代码
                  数量              产品      月份                        A      一月      21              三月      28              二月      139              B      一月      51              三月      26              二月      23   
  1. df_group.index
复制代码
  1. MultiIndex([('A', '一月'),
  2.             ('A', '三月'),
  3.             ('A', '二月'),
  4.             ('B', '一月'),
  5.             ('B', '三月'),
  6.             ('B', '二月')],
  7.            names=['产品', '月份'])
复制代码
可以看到分组聚合运算之后原来df的索引是整数索引,而分组聚合后索引变成了每行一个唯一分组的索引

用AI解释的原话就是:在Pandas中,当你使用groupby方法并传入两个或更多列名作为分组键时,Pandas会创建一个多级索引(也称为层次化索引或复合索引)来标识每个唯一的分组。这是因为每个分组现在由多个列的值共同定义,所以需要一个能够反映这种多维分组结构的索引。

我的学习小插曲

这是一个比较方便快捷的做到分组汇总的方法,如果是我以前做的话是这样的:
  1. # 先聚合运算再赋值到新列
  2. df_sum = df.copy()
  3. df_sum['汇总'] = df.groupby(['产品','月份'])['数量'].transform('sum')
  4. df_sum
复制代码
            月份      产品      数量      汇总                  0      三月      B      23      26              1      一月      B      26      51              2      二月      A      48      139              3      三月      B      3      26              4      一月      B      25      51              5      二月      A      20      139              6      三月      A      14      28              7      二月      A      25      139              8      一月      A      21      21              9      三月      A      14      28              10      二月      A      46      139              11      二月      B      23      23   
  1. df_sum.drop_duplicates(subset=['产品','月份'],inplace=True)
  2. df_sum.drop(columns='数量',inplace=True)
  3. df_sum
复制代码
            月份      产品      汇总                  0      三月      B      26              1      一月      B      51              2      二月      A      139              6      三月      A      28              8      一月      A      21              11      二月      B      23    这就是我以前做的步骤,这种步骤做完了并不能让你直观的看到A、B每个月份的总数量是多少,还是达不到想要的效果也不美观。

当时只会傻傻的这样用,然后当自己要做成多层级索引的时候再打开excel表格自己手工做。

后来看别人写的代码了解到,agg和transform返回的结果是不一样的。agg返回的是一个新的以分组作为索引的dataframe或series,而transform返回的是一个与原dataframe等长的值

它们的区别就简单带过一下,主要是多层索引

多层索引的好处就是可以很直观的看到分组的整体数据,不用看的那么密密麻麻。当然也可以自己创建多层级索引的dataframe。

创建多层级索引dataframe

pandas中有个MultiIndex函数提供了三种方法创建多层级索引,分别是:.from_tuples()、.from_arrays()和.from_product(),

按照很多人推荐的且我自己也用过,第三种.from_product()是最好用的
  1. # 创建多层级索引的dataframe
  2. index = pd.MultiIndex.from_product([['A', 'B'], ['一月', '二月','三月']], names=['产品', '月份'])
  3. values_2 = np.random.randint(1,50,size=6)
  4. df_2 = pd.DataFrame(data=values_2,index=index,columns=['数量'])
  5. df_2
复制代码
                  数量              产品      月份                        A      一月      12              二月      28              三月      47              B      一月      35              二月      6              三月      23   
  1. # 把groupby加agg返回的series拿过来对比查看
  2. df_group    # 原来返回的是series但我转成了dataframe
复制代码
                  数量              产品      月份                        A      一月      21              三月      28              二月      139              B      一月      51              三月      26              二月      23    可以看到不管是groupby加agg返回的series还是自己创建的多层索引dataframe,他们的索引都是一样的(但顺序不完全一样哈哈哈)。
说到这可能有些时候又需要把产品放到列索引中,那pandas也留了两个函数stack()和unstack(),可以对索引进行转换
索引转换

stack()函数可以把列索引压入到行索引当中,unstack()把行索引展开到列索引中。默认展开的顺序是从里往外,展开后也是在索引的最里层,最里面一层的序号是-1。

我这里想把产品这行索引转换成列索引所以使用unstack()函数。

DataFrame.unstack(level=-1, fill_value=None)

● level:要展开的级别编号或名称。默认为-1,即最内层的级别。

● fill_value:用于填充缺失值的值。默认为None,即不填充。
  1. df_group.unstack(-2)
复制代码
            数量              产品      A      B              月份                              一月      21      51              三月      28      26              二月      139      23    产品的行索引在最外层从-1往外数是-2,可以看到转换之后产品这行索引从最外层跑到了列索引的最里层。

能讲的就这么多了主要还是想分享一个在学习的过程中遇到的事情。

上面用到的一些函数不会的可以找找AI或菜鸟教程。

[code][/code]
来源:https://www.cnblogs.com/Xavier-Hsiang/p/18570680
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具