美文网首页python
Python--MultiIndex多层次索引学习

Python--MultiIndex多层次索引学习

作者: 李小李的路 | 来源:发表于2019-06-13 13:32 被阅读0次

Python3 pandas.MultiIndex 概述

  • 层次化索引(hierarchical indexing)在一个轴上拥有多个(两个以上)索引级别,使用户能以低维度形式处理高维度数据。
    • levels:每个等级上轴标签的唯一值
    • labels:以整数来表示每个level上标签的位置
    • sortorder:按照指定level上的标签名称的字典顺序进行排序(可选参数)
    • names:index level的名称
    • copy:布尔值,默认为False。是否拷贝元数据产生新的对象
    • verify_integrity:布尔值,默认为Ture。检查levels/labels是否持续有效

入门级demo学习

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Time    : 2019-06-13 10:11
# @Author  : LiYahui
# @Description : python multiindex demo
import pandas as pd
import numpy as np
data = pd.Series(np.random.randn(10),
              index=[['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'd', 'd'],
                     [1, 2, 3, 1, 2, 3, 1, 2, 2, 3]])
print("----------print data---------------")
print(data)
'''
a  1   -0.902378
   2   -1.512923
   3   -1.082350
b  1   -0.900975
   2   -1.723988
   3   -0.791613
c  1   -1.631530
   2    2.290227
d  2    0.530892
   3    1.199453
dtype: float64
'''
print("----------print data.index-------------")
print(data.index)
'''
MultiIndex(levels=[['a', 'b', 'c', 'd'], [1, 2, 3]],
           codes=[[0, 0, 0, 1, 1, 1, 2, 2, 3, 3], [0, 1, 2, 0, 1, 2, 0, 1, 1, 2]])

'''
print("----------print data.index.levels[0]----------------")
print(data.index.levels[0])
'''
Index(['a', 'b', 'c', 'd'], dtype='object')
'''
print("----------print data.index.levels[1]----------------")
print(data.index.levels[1])
'''
Int64Index([1, 2, 3], dtype='int64')
'''
  • 总结分析如下:
    • level中的唯一标签值集合分别为[‘a’, ‘b’, ‘c’, ‘d’]和[1, 2, 3]。
    • data.index.levels[0]上的标签abcd对应的索引为0123。data.index.levels[1]上的标签123对应的索引为012。
    • 外层level的label值[0, 0, 0, 1, 1, 1, 2, 2, 3, 3]表示对应的标签值分别出现几次:a和b为3次,c和d为2次
    • 内层level的label值[0, 1, 2, 0, 1, 2, 0, 1, 1, 2]按个数与外层label相对应。例如:外层a出现3次,则内层label的前3个值与a相对应,这三个索引值为0,1,2,分别对应1,2,3。

MultiIndex创建的方式

第一种

  • 我们在创建Series或DataFrame时,可以通过给index(columns)参数传递多维数组,进而构建多维索引。【数组中每个维度对应位置的元素,组成每个索引值】
  • 多维索引的也可以设置名称(names属性),属性的值为一维数组,元素的个数需要与索引的层数相同(每层索引都需要具有一个名称)。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Time    : 2019-06-13 10:52
# @Author  : LiYahui
# @Description : MultiIndex demo
import pandas as pd
import numpy as np

# 创建多层索引的第一种方式
# 创建Series对象,具有单层索引。
s1 = pd.Series([1, 2, 3], index=["a", "b", "c"])
print(s1)
'''
a    1
b    2
c    3
dtype: int64
'''

# 创建多层索引。多层索引需要一个二维的数组,每个元素(一维数组)来指定每个层级的索引。顺序
# 由高层(左边)到底层(右边)。
s2 = pd.Series([1, 2, 3, 4], index=[["a", "a", "b", "b"], ["c", "d", "e", "f"], ["m", "m", "k", "t"]])
print(s2)
'''
a  c  m    1
   d  m    2
b  e  k    3
   f  t    4
dtype: int64
'''
print("-------df--------")
df = pd.DataFrame(np.random.random(size=(4, 4)), index=[["上半年", "上半年", "下半年", "下半年"],
                                                        ["第一季度", "第二季度", "第三季度", "第四季度"]],
                  columns=[["水果", "水果", "蔬菜", "蔬菜"], ["苹果", "葡萄", "白菜", "萝卜"]])
print(df)
'''
                水果                  蔬菜          
                苹果        葡萄        白菜        萝卜
上半年 第一季度  0.356637  0.358602  0.402864  0.550727
    第二季度  0.963110  0.010293  0.378511  0.051015
下半年 第三季度  0.098882  0.394281  0.554502  0.676566
    第四季度  0.828770  0.506423  0.681128  0.542206
'''
print(df.index)
'''
MultiIndex(levels=[['上半年', '下半年'], ['第一季度', '第三季度', '第二季度', '第四季度']],
           codes=[[0, 0, 1, 1], [0, 2, 1, 3]])
'''
print(df.columns)
'''
MultiIndex(levels=[['水果', '蔬菜'], ['白菜', '苹果', '萝卜', '葡萄']],
           codes=[[0, 0, 1, 1], [1, 3, 0, 2]])
'''
# 如果是单层索引,我们可以通过索引对象的name属性来设置索引的名称。
s2 = pd.Series([1, 2, 3, 4], index=["a", "b", "c", "d"])
s2.index.name = "索引名称"
print("--------s2----------")
print(s2)
'''
索引名称
a    1
b    2
c    3
d    4
dtype: int64
'''
# 对于多层索引,也可以设置索引的名称,此时,设置名称的属性为names(通过一维数组来设置)。
# 每层索引都具有名称。
# 修改df的索引
df.index.names = ["年度", "季度"]
df.columns.names = ["大类别", "小类别"]
print(df)
'''
大类别             水果                  蔬菜          
小类别             苹果        葡萄        白菜        萝卜
年度  季度                                          
上半年 第一季度  0.078253  0.961293  0.770540  0.267522
    第二季度  0.845138  0.239290  0.208779  0.347256
下半年 第三季度  0.869534  0.148100  0.046563  0.753004
    第四季度  0.926966  0.305344  0.379041  0.467218
'''

第二种

  • 我们可以通过MultiIndex类的相关方法,预先创建一个MultiIndex对象,然后作为Series与DataFrame中的index(或columns)参数值。同时,可以通过names参数指定多层索引的名称。
  • from_arrays:接收一个多维数组参数,高维指定高层索引,低维指定底层索引。
  • from_tuples:接收一个元组的列表,每个元组指定每个索引(高维索引,低维索引)。
  • from_product:接收一个可迭代对象的列表,根据多个可迭代对象元素的笛卡尔积进行创建索引。

from_product相对于前两个方法而言,实现相对简单,但是,也存在局限。

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Time    : 2019-06-13 11:13
# @Author  : LiYahui
# @Description :multiindex demo
import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.random(size=(4, 4)), index=[["上半年", "上半年", "下半年", "下半年"],
                                                        ["第一季度", "第二季度", "第三季度", "第四季度"]],
                  columns=[["水果", "水果", "蔬菜", "蔬菜"], ["苹果", "葡萄", "白菜", "萝卜"]])
print(df)
'''
                水果                  蔬菜          
                苹果        葡萄        白菜        萝卜
上半年 第一季度  0.645330  0.408014  0.121088  0.106337
    第二季度  0.671892  0.212711  0.792635  0.031329
下半年 第三季度  0.063841  0.513930  0.342464  0.885220
    第四季度  0.091936  0.745129  0.905859  0.760001
'''
# 创建多层索引的第二种方式
# ------------from_arrays-------------------
# from_arrays 参数为一个二维数组,每个元素(一维数组)来分别制定每层索引的内容。
mindex_arrsys = pd.MultiIndex.from_arrays([["上半年", "上半年", "下半年", "下半年"], ["1季度", "2季度", "3季度", "4季度"]])
df2 = pd.DataFrame(np.random.random(size=(4, 4)), index=mindex_arrsys)
print(df2)
'''
                0         1         2         3
上半年 1季度  0.578044  0.636138  0.497155  0.389131
    2季度  0.195453  0.623200  0.769118  0.637451
下半年 3季度  0.562462  0.629691  0.684193  0.981682
    4季度  0.873525  0.489149  0.883518  0.252548
'''
# ------------from_tuples-------------------
# from_tuples 参数为一个(嵌套的)可迭代对象,元素为元祖类型。元祖的格式为:(高层索引内容,低层索引内容)
mindex_tuples = pd.MultiIndex.from_tuples([("上半年", "1季度"), ("上半年", "2季度"), ("下半年", "3季度"), ("下半年", "4季度")])
df3 = pd.DataFrame(np.random.random(size=(4, 4)), index=mindex_tuples)
print(df3)
'''
                0         1         2         3
上半年 1季度  0.843825  0.242793  0.132814  0.024581
    2季度  0.404961  0.870869  0.134744  0.220976
下半年 3季度  0.196361  0.074073  0.588173  0.181438
    4季度  0.936489  0.246351  0.941209  0.144210
'''
# ------------from_products-------------------
# 使用笛卡尔积的方式来创建多层索引。参数为嵌套的可迭代对象。结果为使用每个一维数组中的元素与其他一维数组中的元素来生成
# 索引内容。
mindex_products = pd.MultiIndex.from_product([["a", "b"], ["c", "d"]], names=["outer", "inner"])
print(mindex_products)
'''
MultiIndex(levels=[['a', 'b'], ['c', 'd']],
           codes=[[0, 0, 1, 1], [0, 1, 0, 1]],
           names=['outer', 'inner'])
'''
print(pd.MultiIndex.from_arrays([["a", "a", "b", "b"], ["c", "d", "c", "d"]]))
'''
MultiIndex(levels=[['a', 'b'], ['c', 'd']],
           codes=[[0, 0, 1, 1], [0, 1, 0, 1]])
'''
print(pd.MultiIndex.from_arrays([["a", "a", "b"], ["c", "d", "d"]]))
'''
MultiIndex(levels=[['a', 'b'], ['c', 'd']],
           codes=[[0, 0, 1], [0, 1, 1]])
'''

# MultiIndex的三个类方法,可以创建MultiIndex类型的对象。三种方式相比,第三种方式(笛卡尔积的方式)更加简便,但是,
# 其也具有一定的局限:两两组合必须都存在,否则,就不能使用这种方式。
# 在创建多层索引对象时,可以通过names参数来指定每个索引层级的名称。

df4 = pd.DataFrame(np.random.random(size=(4, 4)),index=mindex_products)
print(df4)
print(df4.index)
'''
                    0         1         2         3
outer inner                                        
a     c      0.213218  0.561547  0.224423  0.764169
      d      0.296970  0.557486  0.809295  0.300886
b     c      0.134809  0.111138  0.619714  0.223240
      d      0.707181  0.872395  0.800698  0.676075
MultiIndex(levels=[['a', 'b'], ['c', 'd']],
           codes=[[0, 0, 1, 1], [0, 1, 0, 1]],
           names=['outer', 'inner'])
'''
# 还有第三种方式(因为繁琐,所以不用),最直接的方式:
mindex = pd.MultiIndex(levels=[['a', 'b'], ['c', 'd']],
                       codes=[[0, 0, 1, 1], [0, 1, 0, 1]],
                       names=['outer', 'inner'])
print(mindex)
'''
MultiIndex(levels=[['a', 'b'], ['c', 'd']],
           codes=[[0, 0, 1, 1], [0, 1, 0, 1]],
           names=['outer', 'inner'])
'''

多层索引操作

  • 对于多层索引,同样也支持单层索引的相关操作,例如,索引元素,切片,索引数组选择元素等。我们也可以根据多级索引,按层次逐级选择元素。
  • 多层索引的优势:通过创建多层索引,我们就可以使用高层次的索引,来操作整个索引组的数据。
  • 格式:
    • s[操作]
    • s.loc[操作]
    • s.iloc[操作]
      其中,操作可以是索引,切片,数组索引,布尔索引。

Series多层索引

  • 通过loc(标签索引)操作,可以通过多层索引,获取该索引所对应的一组值。
  • 通过iloc(位置索引)操作,会获取对应位置的元素值(与是否多层索引无关)。
  • 通过s[操作]的行为有些诡异,建议不用。
  • 对于索引(单级),首先按照标签选择,如果标签不存在,则按照位置选择。
  • 对于多级索引,则按照标签进行选择。
  • 对于切片,如果提供的是整数,则按照位置选择,否则按照标签选择。
  • 对于数组索引, 如果数组元素都是整数,则根据位置进行索引,否则,根据标签进行索引(此时如果标签不存在,也不会出现错误)。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Time    : 2019-06-13 11:28
# @Author  : LiYahui
# @Description : 位置选择
import pandas as pd

s = pd.Series([1, 2, 3, 4], index=[["a", "a", "b", "b"], ["c", "d", "e", "f"]])
print(s)
'''
a  c    1
   d    2
b  e    3
   f    4
dtype: int64
'''
# 多层索引的优势,可以一次获取一组元素(值)
print(s.loc["a"])
'''
c    1
d    2
dtype: int64
'''
# 也可以沿着索引层次进行访问。
print(s.loc["a", "d"]) # 访问指定坐标的元素值
'''
2
'''
# 通过位置索引访问元素,与多层索引没有任何关系。
print(s.iloc[0])
'''
1
'''

# 切片
print(s.loc["a":"b"])
'''
a  c    1
   d    2
b  e    3
   f    4
dtype: int64
'''
# 行index上的序号类型的切片
print(s.iloc[0:2])
'''
a  c    1
   d    2
b  e    3
   f    4
dtype: int64
'''

DataFrame多层索引

  • 通过loc(标签索引)操作,可以通过多层索引,获取该索引所对应的一组值。
  • 通过iloc(位置索引)操作,会获取对应位置的一行(与是否多层索引无关)。
  • 通过s[操作]的行为有些诡异,建议不用。
  • 对于索引,根据标签获取相应的列(如果是多层索引,则可以获得多列)。
  • 对于数组索引, 根据标签,获取相应的列(如果是多层索引,则可以获得多列)。
  • 对于切片,首先按照标签进行索引,然后再按照位置进行索引(取行)。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Time    : 2019-06-13 11:28
# @Author  : LiYahui
# @Description : 位置选择
import pandas as pd
data=[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]
df=pd.DataFrame(data)
print(df)
'''
    0   1   2   3
0   1   2   3   4
1   5   6   7   8
2   9  10  11  12
3  13  14  15  16
'''
# 指定行索引
df.index=[["a", "a", "b", "b"], ["c", "d", "c", "d"]]
# 指定列索引
df.columns=[["x", "x", "y", "y"], ["z", "u", "z", "u"]]
print("-----------指定行和列索引之后的数据值---------------")
print(df)
'''
      x       y    
      z   u   z   u
a c   1   2   3   4
  d   5   6   7   8
b c   9  10  11  12
  d  13  14  15  16
'''
print('-------df.loc["a"]------------')
print(df.loc["a"]) # 对应的外层索引的切片
'''
   x     y   
   z  u  z  u
c  1  2  3  4
d  5  6  7  8
'''
print('--------df.loc["a", "c"]-----------')
print(df.loc["a", "c"])   #取的是对应的行数据
'''
x  z    1
   u    2
y  z    3
   u    4
'''
print('------df["x", "z"])--------')
print(df["x", "z"]) #取的是列数据
'''
a  c     1
   d     5
b  c     9
   d    13
Name: (x, z), dtype: int64
'''

# 通过位置访问元素与是否多层索引无关。
print('----------df.iloc[0])-----------------')
print(df.iloc[0])
'''
x  z    1
   u    2
y  z    3
   u    4
Name: (a, c), dtype: int64
'''

交换索引

我们可以调用DataFrame对象的swaplevel方法来交换两个层级索引。该方法默认对倒数第2层与倒数第1层进行交换。我们也可以指定交换的层。层次从0开始,由外向内递增(或者由上到下递增),也可以指定负值,负值表示倒数第n层。除此之外,我们也可以使用层次索引的名称来进行交换。

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Time    : 2019-06-13 13:07
# @Author  : LiYahui
# @Description : 
# 交换索引的层级,可以以一种不同的方式来进行展示(统计)。
import pandas as pd
data=[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]]
df = pd.DataFrame(data, index=[["a", "a", "b", "b"],
            ["north", "north", "south", "south"], [2017, 2018, 2017, 2018]])
print(df)
'''
               0   1   2   3
a north 2017   1   2   3   4
        2018   5   6   7   8
b south 2017   9  10  11  12
        2018  13  14  15  16
'''
# 层级:从外层到内层,值为0, 1, 2……,同时,层级也可以为负值,表示倒数第n个层级(由内层到外层)。
# 例如,-1表示最内层。
# 如果没有显式指定交换的层级,则默认交换最内层的两个层级。
df = df.swaplevel(0, 2)
print(df)
'''
               0   1   2   3
2017 north a   1   2   3   4
2018 north a   5   6   7   8
2017 south b   9  10  11  12
2018 south b  13  14  15  16
'''
# 索引名字的作用。
# 除了数值来指定索引的层级外,我们也可以通过索引的名字来指定索引的层级。
df.index.names = ["x", "area", "year"]
df.swaplevel("area", "year")
print(df)
'''
                  0   1   2   3
x    area  year                
2017 north a      1   2   3   4
2018 north a      5   6   7   8
2017 south b      9  10  11  12
2018 south b     13  14  15  16
'''
df.sort_index()
print(df)
'''
                 0   1   2   3
x    area  year                
2017 north a      1   2   3   4
2018 north a      5   6   7   8
2017 south b      9  10  11  12
2018 south b     13  14  15  16
'''

索引排序

我们可以使用sort_index方法对索引进行排序处理。

  • level:指定根据哪一层进行排序,默认为最外(上)层。该值可以是数值,索引名,或者是由二者构成的列表。
  • inplace:是否就地修改。默认为False。

# 层级索引的排序
df = pd.DataFrame(data, index=[["b", "a", "c", "c"],
            ["c", "y", "k", "k"], [3, -2, 5, 2]])
print(df)
'''
         0   1   2   3
b c  3   1   2   3   4
a y -2   5   6   7   8
c k  5   9  10  11  12
     2  13  14  15  16
'''
# 在对索引进行排序时,可以通过level参数指定索引的层级(排序的层级)。
# 如果没有显式指定,则默认为最外层的层级(层级为0)。
# 当我们对某个层级进行排序时,该层级的所有内层层级也会进行排序。
print(df.sort_index())
'''
         0   1   2   3
a y -2   5   6   7   8
b c  3   1   2   3   4
c k  2  13  14  15  16
     5   9  10  11  12
'''
print(df.sort_index(level=1))
'''
         0   1   2   3
b c  3   1   2   3   4
c k  2  13  14  15  16
     5   9  10  11  12
a y -2   5   6   7   8
'''

索引堆叠

  • 通过DataFrame对象的stack方法,可以进行索引堆叠,即将指定层级的列转换成行。
  • level:指定转换的层级,默认为-1。
    *详见 Python--pandas--unstack() 与stack()

取消堆叠

  • 通过DataFrame对象的unstack方法,可以取消索引堆叠,即将指定层级的行转换成列。
  • level:指定转换的层级,默认为-1。
  • fill_value:指定填充值。默认为NaN。
  • 详见: Python--pandas--unstack() 与stack()

设置索引

  • 在DataFrame中,如果我们需要将现有的某一(几)列作为索引列,可以调用set_index方法来实现。
  • drop:是否丢弃作为新索引的列,默认为True。
  • append:是否以追加的方式设置索引,默认为False。
  • inplace:是否就地修改,默认为False。
  • 详见Python-pandas--set_index与reset_index

重置索引

  • 调用在DataFrame对象的reset_index,可以重置索引。该操作与set_index正好相反。
  • level:重置索引的层级,默认重置所有层级的索引。如果重置所有索引,将会创建默认整数序列索引。
  • drop:是否丢弃重置的索引列,默认为False。
  • inplace:是否就地修改,默认为False。
  • 详见 Python-pandas--set_index与reset_index

相关文章

网友评论

    本文标题:Python--MultiIndex多层次索引学习

    本文链接:https://www.haomeiwen.com/subject/pskjfctx.html