Pandas MultiIndex对象

分层/多级索引,因为它为一些非常复杂的数据分析和操作提供了可能性,特别是对于处理更高维度的数据。从本质上讲,它使你能在较低维度的数据结构(如Series(1d)和DataFrame(2d))中存储和操作具有任意数量维度的数据。

创建MultiIndex

MultiIndex 对象是标准Index对象的扩展, 你可以将 MultiIndex 视为元组构成的列表,其中每个元组都是唯一的, 它与Index的区别是, Index 可以视为数字或者字符串构成的列表。可以从数组列表(使用MultiIndex.from_arrays),元组列表(使用MultiIndex.from_tuples)或交叉迭代集(使用MultiIndex.from_product)创建MultiIndex。当构造函数传递元组列表时,它将尝试返回 MultiIndex。以下示例演示了创建 MultiIndexes 的不同方法。

from_tuples

创建一个元祖构成的列表

arrays = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
            ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']]

tuples = list(zip(*arrays))
print(tuples)
'''
[('bar', 'one'), ('bar', 'two'),
 ('baz', 'one'), ('baz', 'two'), 
 ('foo', 'one'), ('foo', 'two'), 
 ('qux', 'one'), ('qux', 'two')]

'''

使用 from_tuples 来创建 MultiIndex:

arrays = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
            ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']]

tuples = list(zip(*arrays))
print(tuples)
'''
[('bar', 'one'), ('bar', 'two'),
 ('baz', 'one'), ('baz', 'two'), 
 ('foo', 'one'), ('foo', 'two'), 
 ('qux', 'one'), ('qux', 'two')]

'''

from_arrays

如果说 from_tuples 接受的参数是””的列表, 那么 from_arrays 接受的参数是就是””的列表:

arrays = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
            ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']]

index = pd.MultiIndex.from_arrays(arrays)
s = pd.Series(np.random.randn(8), index=index)

print(s)
'''
bar  one   -0.268434
     two   -0.026027
baz  one   -0.658945
     two    0.283218
foo  one    1.054412
     two    1.977076
qux  one   -0.563627
     two   -0.156421
dtype: float64
'''

不过为了简便, 我们通常可以直接在Series的构造函数中使用:

arrays = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
            ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']]

s = pd.Series(np.random.randn(8), index=arrays)
print(s)
'''
bar  one   -1.411561
     two    0.667025
baz  one   -0.079449
     two   -0.715518
foo  one   -1.844785
     two    0.257104
qux  one   -0.776653
     two   -1.159284
dtype: float64
'''

from_product

假如我们有两个 list , 这两个 list 内的元素相互交叉, 两两搭配, 这就是两个 list 的product:

lists = [['bar', 'baz', 'foo', 'qux'], ['one', 'two']]

index = pd.MultiIndex.from_product(lists, names=['first', 'second'])
s = pd.Series(np.random.randn(len(index)), index=index)
print(s)
'''
first  second
bar    one      -1.309958
       two       0.379085
baz    one       0.739266
       two      -0.165164
foo    one      -0.022698
       two      -0.006190
qux    one       0.299748
       two      -0.864639
dtype: float64
'''

MultiIndex.names

你可以为 MultiIndex 的各个层起名字, 这就是 names 属性:

print(s.index.names)
#['first', 'second']

s.index.names = ['FirstLevel', 'SecondLevel']
print(s.index.names)
#['FirstLevel', 'SecondLevel']

MultiIndex可以作为列名称

Series 和 DataFrame 的列名称属性就是columns, 也可以是一个 MultiIndex 对象:

df = pd.DataFrame(np.random.randn(3, 8), index=['A', 'B', 'C'], columns=index)
print(df)
'''
FirstLevel        bar                 baz  ...       foo       qux          
SecondLevel       one       two       one  ...       two       one       two
A            1.127256  1.453003  0.025833  ... -1.258916  0.711659 -1.460118
B            1.589573  2.057785  0.028412  ... -1.678021 -0.662083 -1.044907
C           -0.879705  0.730224 -0.003296  ... -0.446753 -1.694061  1.440663

[3 rows x 8 columns]
'''

获取各水平的值

方法get_level_values将返回特定级别的每个位置的标签向量

print(index.get_level_values(0))
'''
Index(['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
 dtype='object', name='FirstLevel')

'''

如果你给 index 设置了名称, 那么你可以直接使用名称来获取水平值:

print(index.get_level_values('FirstLevel'))
'''
Index(['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
 dtype='object', name='FirstLevel')

'''

选择数据

这可能是MultiIndex最重要的功能之一。

print(df)
'''
FirstLevel        bar                 baz  ...       foo       qux          
SecondLevel       one       two       one  ...       two       one       two
A            1.134195 -0.351198  0.218614  ... -0.755923  0.129988 -0.052183
B           -0.308971  1.399584 -0.894162  ... -1.022070  0.045872  1.539032
C           -0.399760  0.351285  1.069002  ... -0.771437  2.350300 -0.922563

[3 rows x 8 columns]
'''

获取 FirstLevel 是 bar 的所有数据

print(df['bar'])
'''
SecondLevel       one       two
A            0.204079  0.635272
B            1.691298 -0.449358
C           -1.236855 -1.144767
'''

获取FirstLevel是bar, SecondLevel是one的所有数据:

print(df['bar']['one'])
'''
A    0.121725
B    1.130435
C   -0.011153
Name: one, dtype: float64
'''

需要注意的是, 结果选择输出的结果的columns已经改变:

print(df['bar'].columns)
#Index(['one', 'two'], dtype='object', name='SecondLevel')

如果你要选择第二层的列名为 one 的所有数据, 你需要借助 xs 方法:

print(df.xs('bar', level=0, axis=1))
'''
SecondLevel       one       two
A           -1.493262 -0.704469
B            3.509268 -1.283146
C           -0.056974  0.710284
'''
print(df.xs('one', level=1, axis=1))
'''
FirstLevel       bar       baz       foo       qux
A           0.537299 -1.054771  0.144664 -0.940659
B          -0.560000 -0.952308 -1.667759 -1.480754
C           0.733805  0.930315 -0.144840 -1.261983
'''

或者使用名称代替数字:

print(df.xs('one', level='SecondLevel', axis='columns'))
'''
FirstLevel       bar       baz       foo       qux
A           0.537299 -1.054771  0.144664 -0.940659
B          -0.560000 -0.952308 -1.667759 -1.480754
C           0.733805  0.930315 -0.144840 -1.261983
'''

axis, 它不仅可以用来选择列, 也可以用来选择行:

print(s)
'''
FirstLevel  SecondLevel
bar         one            1.262375
            two            0.211678
baz         one           -0.207278
            two            0.386925
foo         one           -0.010342
            two           -1.775980
qux         one           -0.981227
            two           -2.159368
dtype: float64
'''

print(s.xs('one', level='SecondLevel', axis='index'))
'''
FirstLevel
bar    0.783906
baz    1.159497
foo   -1.361565
qux   -0.838874
dtype: float64
'''

选择行

把 df 进行转置, 然后看看一些选择行的操作:

df = df.T
print(df)
'''
                               A         B         C
FirstLevel SecondLevel                              
bar        one          0.923159  3.412767 -2.821506
           two          2.641013  0.229025  1.251807
baz        one          0.900035  0.874848  0.246452
           two         -1.326872  0.647462 -0.088361
foo        one          1.730885 -0.732980 -0.373840
           two         -1.369826 -1.532940 -0.204242
qux        one          0.305318  0.929807 -0.331868
           two          1.110960 -0.869984  0.990428
'''

选择 FirstLevel 是 bar, SecondLevel 是 two 的数据:

print(df.loc[('bar', 'two')])
'''
A   -0.096414
B    0.796829
C   -0.571624
Name: (bar, two), dtype: float64
'''

多重索引的标签要一元组的形式('bar', 'two'),不能是列表的形式['bar', 'two']

下面的用法是等效的:

print(df.loc['bar'].loc['two'])
'''
A   -0.755750
B    0.387714
C    1.164027
Name: two, dtype: float64
'''

选择行的同时也能选择列:

print(df.loc[('bar', 'two'), 'A'])
#-0.5189738423458226

还能使用切片操作:

print(df.loc['baz': 'foo'])
'''
                               A         B         C
FirstLevel SecondLevel                              
baz        one         -1.507232 -0.207591  1.242952
           two         -0.424180 -1.741234 -1.205756
foo        one          0.858520  1.594259 -1.314260
           two         -0.711255  0.356851 -0.276307
'''

或许, 使用更多的是这样:

print(df.loc[('bar', 'two'): ('baz', 'two')])
'''
FirstLevel SecondLevel                              
bar        two         -1.293961 -0.931613  0.090003
baz        one         -0.509716 -0.802122  1.583681
           two         -0.613451  0.121745  0.895646
'''

推荐使用xs, 它可以使你的代码更容易被别人理解, 而且选择行和列都用统一的方式:

print(df.xs('two', level='SecondLevel', axis='index'))
'''
                   A         B         C
FirstLevel                              
bar        -1.201396 -2.257291  0.831497
baz        -1.204905 -0.351232 -0.025386
foo         0.987691 -0.454322  0.679079
qux         0.813230  0.073436 -0.951928
'''

MultiIndex对象属性

m_index1=pd.Index([("A","x1"),("A","x2"),("B","y1"),("B","y2"),("B","y3")],name=["class1","class2"])
print(m_index1)
'''
MultiIndex([('A', 'x1'),
            ('A', 'x2'),
            ('B', 'y1'),
            ('B', 'y2'),
            ('B', 'y3')],
           names=['class1', 'class2'])
'''
df1=DataFrame(np.random.randint(1,10,(5,3)),index=m_index1)
print(df1)
'''
class1 class2         
A      x1      1  9  2
       x2      5  3  2
B      y1      8  8  6
       y2      9  2  2
       y3      5  6  8
'''
m_index=df1.index
print(m_index[0])
# ('A', 'x1')

print(m_index[1])
# ('A', 'x2')

调用.get_loc().get_indexer()获取标签的下标:

print(m_index.get_loc(("A","x2")))  #1
print(m_index.get_indexer([("A","x2"),("B","y1"),"nothing"]))
#[ 1  2 -1]

MultiIndex 对象使用多个 Index 对象保存索引中每一级的标签:

print(m_index.levels[0])
print(m_index.levels[1])
'''
Index(['A', 'B'], dtype='object', name='class1')
Index(['x1', 'x2', 'y1', 'y2', 'y3'], dtype='object', name='class2')
'''

MultiIndex 对象还有属性 labels 保存标签的下标:

print(m_index.labels[0])
print(m_index.labels[1])
'''
[0 0 1 1 1]
[0 1 2 3 4]
'''
Update time: 2020-05-25

results matching ""

    No results matching ""