• pandas 分层索引


    一、分层索引基础

    Pandas提供了Panel和Panel4D对象解决三维和四维数据的处理需求,但更常用的还是分层索引。分层索引是Pandas的重要特性,允许我们在一个轴向上拥有多个索引层级,它提供了一种在更低维度的形式中处理更高维度数据的方式。也就是如何用Series、DataFrame处理三维、四维等等高维度的数据。

    比如有下面的数据:

    In [168]: s = pd.Series(np.random.randn(9), index=[['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'], [1, 2, 3, 1, 3, 1, 2, 2, 3]])
    In [169]: s
    Out[169]:
    a  1    0.283490
       2    0.295529
       3    0.277676
    b  1    0.487573
       3    0.091161
    c  1    0.285157
       2   -0.806851
    d  2   -0.287969
       3   -0.696511
    dtype: float64
    In [170]: s.index
    Out[170]:
    MultiIndex(levels=[['a', 'b', 'c', 'd'], [1, 2, 3]],
               labels=[[0, 0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 2, 0, 2, 0, 1, 1, 2]])

    MultiIndex就是一个分层索引对象,在打印的时候会进行规整的美化。

    下面看下一些基本的操作:

    In [171]: s['b']
    Out[171]:
    1    0.487573
    3    0.091161
    dtype: float64
    In [172]: s['b':'c']
    Out[172]:
    b  1    0.487573
       3    0.091161
    c  1    0.285157
       2   -0.806851
    dtype: float64
    In [173]: s.loc[['b','d']]
    Out[173]:
    b  1    0.487573
       3    0.091161
    d  2   -0.287969
       3   -0.696511
    dtype: float64
    In [174]: s.loc['b','d'] # 这样不可以
    ---------------------------------------------------------------------------
    IndexingError                             Traceback (most recent call last)
    IndexingError: Too many indexers
    In [175]: s.loc['b',1] # 但是这样可以
    Out[175]: 0.48757273896298425
    In [176]: s.loc[:, 2] # 或者这样
    Out[176]:
    a    0.295529
    c   -0.806851
    d   -0.287969
    dtype: float64

    还可以这样来生成MultiIndex,请体会它的不同之处:

    In [3]: tup = [('beijing',2000),('beijing',2019),
       ...:         ('shanghai',2000),('shanghai',2019),
       ...:         ('guangzhou',2000),('guangzhou',2019)]
    In [4]: values = [10000,100000,6000,60000,4000,40000]
    In [7]: index = pd.MultiIndex.from_tuples(tup) # 利用元组生成MultiIndex
    In [8]: sss = pd.Series(values, index=index) # 提供一个MultiIndex作为索引
    In [9]: sss
    Out[9]:
    beijing    2000     10000
               2019    100000
    shanghai   2000      6000
               2019     60000
    guangzhou  2000      4000
               2019     40000
    dtype: int64

    更多的创建MultiIndex的方法还有:

    • 从列表:pd.MultiIndex.from_arrays([['a','a','b','b'],[1,2,1,2]])
    • 从元组:pd.MultiIndex.from_tuples([('a',1),('a',2),('b',1),('b',2)])
    • 笛卡儿积:pd.MultiIndex.from_product([['a','b'],[1,2]])
    • 直接构造:pd.MultiIndex(levels=[['a','b'],[1,2]],labels=[[0,0,1,1],[0,1,0,1]])

    生成MultiIndex对象后,就可以将这些对象作为参数,在创建Series或者DataFrame时传递给index。或者通过reindex方法更新已有的Series/DataFrame索引。

    分层索引在重塑数据和数组透视表中非常重要。比如,我们可以使用unstack方法将数据在DataFrame中重新排列,也就是展开:

    In [178]: s.unstack()
    Out[178]:
              1         2         3
    a  0.283490  0.295529  0.277676
    b  0.487573       NaN  0.091161
    c  0.285157 -0.806851       NaN
    d       NaN -0.287969 -0.696511
    In [179]: s.unstack().stack()  # 反操作stack
    Out[179]:
    a  1    0.283490
       2    0.295529
       3    0.277676
    b  1    0.487573
       3    0.091161
    c  1    0.285157
       2   -0.806851
    d  2   -0.287969
       3   -0.696511
    dtype: float64

    对于DataFrame对象,每个轴都可以有分层索引,给index或columns提供一个多维数组,就可以分层:

    In [3]: df = pd.DataFrame(np.arange(12).reshape((4, 3)),
       ...:                      index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
       ...:                      columns=[['Ohio', 'Ohio', 'Colorado'],
       ...:                               ['Green', 'Red', 'Green']])
    
    In [4]: df
    Out[4]:
         Ohio     Colorado
        Green Red    Green
    a 1     0   1        2
      2     3   4        5
    b 1     6   7        8
      2     9  10       11

    可以给分层索引自定义名字:

    In [5]: df.index.names
    Out[5]: FrozenList([None, None])
    In [6]: df.index.names = ['key1','key2']
    In [7]: df.columns.names
    Out[7]: FrozenList([None, None])
    In [8]: df.columns.names = ['state','color']
    In [9]: df
    Out[9]:
    state      Ohio     Colorado
    color     Green Red    Green
    key1 key2
    a    1        0   1        2
         2        3   4        5
    b    1        6   7        8
         2        9  10       11
    In [10]: df['Ohio']
    Out[10]:
    color      Green  Red
    key1 key2
    a    1         0    1
         2         3    4
    b    1         6    7
         2         9   10

    二、分层索引进阶

    1、重排序和层级排序

    有时候,我们需要重新排列轴上的层级顺序,或者按照特定的层级的值对数据进行排序。 Pandas的swaplevel方法用于这一功能,层级发生变更,但原数据不变。

    In [11]: df.swaplevel('key1', 'key2')
    Out[11]:
    state      Ohio     Colorado
    color     Green Red    Green
    key2 key1
    1    a        0   1        2
    2    a        3   4        5
    1    b        6   7        8
    2    b        9  10       11

    另外, sort_index方法只能在单一层级上对数据进行排序。在进行层级变换的时候,使用sort_index可以使得结果按照层级进行字典排序:

    In [12]: df.sort_index(level=1)
    Out[12]:
    state      Ohio     Colorado
    color     Green Red    Green
    key1 key2
    a    1        0   1        2
    b    1        6   7        8
    a    2        3   4        5
    b    2        9  10       11
    In [13]: df.swaplevel(0, 1).sort_index(level=0)
    Out[13]:
    state      Ohio     Colorado
    color     Green Red    Green
    key2 key1
    1    a        0   1        2
         b        6   7        8
    2    a        3   4        5
         b        9  10       11

    sort_index(level=1)意思是在第2个层级上进行索引的排序。

    swaplevel(0, 1)的意思是将第0层和第1层的行索引进行交换。

    2、层级的汇总统计

    使用level参数可以指定你想要在某个特定的轴上进行聚合。

    In [15]: df.sum(level='key2')
    Out[15]:
    state  Ohio     Colorado
    color Green Red    Green
    key2
    1         6   8       10
    2        12  14       16
    In [16]: df.sum(level='color', axis=1)
    Out[16]:
    color      Green  Red
    key1 key2
    a    1         2    1
         2         8    4
    b    1        14    7
         2        20   10

    3、使用DataFrame的列进行索引

    在DataFarme的索引操作中,还有一个比较特殊的场景,就是将一些列转换成层级行索引:

    In [17]: df= pd.DataFrame({'a': range(7), 'b': range(7, 0, -1),
        ...:                       'c': ['one', 'one', 'one', 'two', 'two',
        ...:                             'two', 'two'],
        ...:                       'd': [0, 1, 2, 0, 1, 2, 3]})
        ...:
    In [18]: df
    Out[18]:
       a  b    c  d
    0  0  7  one  0
    1  1  6  one  1
    2  2  5  one  2
    3  3  4  two  0
    4  4  3  two  1
    5  5  2  two  2
    6  6  1  two  3
    In [19]: df2 = df.set_index(['c','d'])
    In [20]: df2
    Out[20]:
           a  b
    c   d
    one 0  0  7
        1  1  6
        2  2  5
    two 0  3  4
        1  4  3
        2  5  2
        3  6  1
    In [21]: df.set_index(['c','d'],drop=False)
    Out[21]:
           a  b    c  d
    c   d
    one 0  0  7  one  0
        1  1  6  one  1
        2  2  5  one  2
    two 0  3  4  two  0
        1  4  3  two  1
        2  5  2  two  2
        3  6  1  two  3
    In [22]: df2.reset_index()
    Out[22]:
         c  d  a  b
    0  one  0  0  7
    1  one  1  1  6
    2  one  2  2  5
    3  two  0  3  4
    4  two  1  4  3
    5  two  2  5  2
    6  two  3  6  1
    • set_index(['c','d']),将c列和d列变成了分层的行索引
    • drop=False则保留了原来的列数据
    • reset_indexset_index的反向操作

    4、分层索引的取值与切片

    先看针对Series的操作:

    In [3]: tup = [('beijing',2000),('beijing',2019),
       ...:         ('shanghai',2000),('shanghai',2019),
       ...:         ('guangzhou',2000),('guangzhou',2019)]
    In [4]: values = [10000,100000,6000,60000,4000,40000]
    In [7]: index = pd.MultiIndex.from_tuples(tup)
    In [8]: s = pd.Series(values, index=index)
    In [9]: s
    Out[9]:
    beijing    2000     10000
               2019    100000
    shanghai   2000      6000
               2019     60000
    guangzhou  2000      4000
               2019     40000
    dtype: int64
    In [10]: s['beijing',2019]
    Out[10]: 100000
    In [11]: s['shanghai']
    Out[11]:
    2000     6000
    2019    60000
    dtype: int64
    In [15]: s[:,2000]
    Out[15]:
    beijing      10000
    shanghai      6000
    guangzhou     4000
    dtype: int64
    In [17]: s[s>5000]
    Out[17]:
    beijing    2000     10000
               2019    100000
    shanghai   2000      6000
               2019     60000
    guangzhou  2019     40000
    dtype: int64
    In [18]: s[['shanghai','guangzhou']]
    Out[18]:
    shanghai   2000     6000
               2019    60000
    guangzhou  2000     4000
               2019    40000
    dtype: int64

    再看看DataFrame,需要记住和理解的核心是:

    • 这是一个分层索引DataFrame对象,不是单级的
    • 默认以列为操作对象
    In [19]: df = pd.DataFrame(np.arange(12).reshape((4, 3)),
        ...:             index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
        ...:             columns=[['Ohio', 'Ohio', 'Colorado'],
        ...:             ['Green', 'Red', 'Green']])
        ...:
    In [20]: df
    Out[20]:
         Ohio     Colorado
        Green Red    Green
    a 1     0   1        2
      2     3   4        5
    b 1     6   7        8
      2     9  10       11
    In [23]: df['Ohio','Colorado']  # 不能这么做,因为列索引分层了
    ---------------------------------------------------------------------------
    KeyError                                  Traceback (most recent call last)
    In [24]: df[['Ohio','Colorado']]  # 这样可以
    Out[24]:
         Ohio     Colorado
        Green Red    Green
    a 1     0   1        2
      2     3   4        5
    b 1     6   7        8
      2     9  10       11
    In [25]: df['Ohio','Green']  # 每层提供一个参数
    Out[25]:
    a  1    0
       2    3
    b  1    6
       2    9
    Name: (Ohio, Green), dtype: int32
    In [26]: df.iloc[:2,:2]
    Out[26]:
         Ohio
        Green Red
    a 1     0   1
      2     3   4
    In [28]: df.loc[:,('Ohio','Red')]
    Out[28]:
    a  1     1
       2     4
    b  1     7
       2    10
    Name: (Ohio, Red), dtype: int32

    另外最后要提醒的是:如果MultiIndex不是有序的索引,那么大多数切片操作都会失败!这时候可以使用前面介绍过的sort_index方法先排下序。

  • 相关阅读:
    jqueryUI弹出框问题
    spring data jpa分页
    解决eclipse编辑js和html卡的问题
    web.xml添加编码过滤器
    Apache SolrCloud安装
    搭建zookeeper集群
    html页面读取PDF小案例
    .NET 使用Process调用7_zip解压文件
    .NET 中三种正确的单例写法
    Git 笔记
  • 原文地址:https://www.cnblogs.com/lavender1221/p/12736212.html
Copyright © 2020-2023  润新知