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方法先排下序。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM