Python3 pandas.MultiIndex 概述
- 層次化索引(hierarchical indexing)在一個軸上擁有多個(兩個以上)索引級別,使用戶能以低維度形式處理高維度數(shù)據(jù)。
- levels:每個等級上軸標簽的唯一值
- labels:以整數(shù)來表示每個level上標簽的位置
- sortorder:按照指定level上的標簽名稱的字典順序進行排序(可選參數(shù))
- names:index level的名稱
- copy:布爾值,默認為False。是否拷貝元數(shù)據(jù)產(chǎn)生新的對象
- verify_integrity:布爾值,默認為Ture。檢查levels/labels是否持續(xù)有效
入門級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')
'''
- 總結(jié)分析如下:
- level中的唯一標簽值集合分別為[‘a(chǎn)’, ‘b’, ‘c’, ‘d’]和[1, 2, 3]。
- data.index.levels[0]上的標簽abcd對應(yīng)的索引為0123。data.index.levels[1]上的標簽123對應(yīng)的索引為012。
- 外層level的label值[0, 0, 0, 1, 1, 1, 2, 2, 3, 3]表示對應(yīng)的標簽值分別出現(xiàn)幾次:a和b為3次,c和d為2次
- 內(nèi)層level的label值[0, 1, 2, 0, 1, 2, 0, 1, 1, 2]按個數(shù)與外層label相對應(yīng)。例如:外層a出現(xiàn)3次,則內(nèi)層label的前3個值與a相對應(yīng),這三個索引值為0,1,2,分別對應(yīng)1,2,3。
MultiIndex創(chuàng)建的方式
第一種
- 我們在創(chuàng)建Series或DataFrame時,可以通過給index(columns)參數(shù)傳遞多維數(shù)組,進而構(gòu)建多維索引?!緮?shù)組中每個維度對應(yīng)位置的元素,組成每個索引值】
- 多維索引的也可以設(shè)置名稱(names屬性),屬性的值為一維數(shù)組,元素的個數(shù)需要與索引的層數(shù)相同(每層索引都需要具有一個名稱)。
#!/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
# 創(chuàng)建多層索引的第一種方式
# 創(chuàng)建Series對象,具有單層索引。
s1 = pd.Series([1, 2, 3], index=["a", "b", "c"])
print(s1)
'''
a 1
b 2
c 3
dtype: int64
'''
# 創(chuàng)建多層索引。多層索引需要一個二維的數(shù)組,每個元素(一維數(shù)組)來指定每個層級的索引。順序
# 由高層(左邊)到底層(右邊)。
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屬性來設(shè)置索引的名稱。
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
'''
# 對于多層索引,也可以設(shè)置索引的名稱,此時,設(shè)置名稱的屬性為names(通過一維數(shù)組來設(shè)置)。
# 每層索引都具有名稱。
# 修改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類的相關(guān)方法,預先創(chuàng)建一個MultiIndex對象,然后作為Series與DataFrame中的index(或columns)參數(shù)值。同時,可以通過names參數(shù)指定多層索引的名稱。
- from_arrays:接收一個多維數(shù)組參數(shù),高維指定高層索引,低維指定底層索引。
- from_tuples:接收一個元組的列表,每個元組指定每個索引(高維索引,低維索引)。
- from_product:接收一個可迭代對象的列表,根據(jù)多個可迭代對象元素的笛卡爾積進行創(chuàng)建索引。
from_product相對于前兩個方法而言,實現(xiàn)相對簡單,但是,也存在局限。
#!/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
'''
# 創(chuàng)建多層索引的第二種方式
# ------------from_arrays-------------------
# from_arrays 參數(shù)為一個二維數(shù)組,每個元素(一維數(shù)組)來分別制定每層索引的內(nèi)容。
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 參數(shù)為一個(嵌套的)可迭代對象,元素為元祖類型。元祖的格式為:(高層索引內(nèi)容,低層索引內(nèi)容)
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-------------------
# 使用笛卡爾積的方式來創(chuàng)建多層索引。參數(shù)為嵌套的可迭代對象。結(jié)果為使用每個一維數(shù)組中的元素與其他一維數(shù)組中的元素來生成
# 索引內(nèi)容。
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的三個類方法,可以創(chuàng)建MultiIndex類型的對象。三種方式相比,第三種方式(笛卡爾積的方式)更加簡便,但是,
# 其也具有一定的局限:兩兩組合必須都存在,否則,就不能使用這種方式。
# 在創(chuàng)建多層索引對象時,可以通過names參數(shù)來指定每個索引層級的名稱。
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'])
'''
多層索引操作
- 對于多層索引,同樣也支持單層索引的相關(guān)操作,例如,索引元素,切片,索引數(shù)組選擇元素等。我們也可以根據(jù)多級索引,按層次逐級選擇元素。
- 多層索引的優(yōu)勢:通過創(chuàng)建多層索引,我們就可以使用高層次的索引,來操作整個索引組的數(shù)據(jù)。
- 格式:
- s[操作]
- s.loc[操作]
- s.iloc[操作]
其中,操作可以是索引,切片,數(shù)組索引,布爾索引。
Series多層索引
- 通過loc(標簽索引)操作,可以通過多層索引,獲取該索引所對應(yīng)的一組值。
- 通過iloc(位置索引)操作,會獲取對應(yīng)位置的元素值(與是否多層索引無關(guān))。
- 通過s[操作]的行為有些詭異,建議不用。
- 對于索引(單級),首先按照標簽選擇,如果標簽不存在,則按照位置選擇。
- 對于多級索引,則按照標簽進行選擇。
- 對于切片,如果提供的是整數(shù),則按照位置選擇,否則按照標簽選擇。
- 對于數(shù)組索引, 如果數(shù)組元素都是整數(shù),則根據(jù)位置進行索引,否則,根據(jù)標簽進行索引(此時如果標簽不存在,也不會出現(xiàn)錯誤)。
#!/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
'''
# 多層索引的優(yōu)勢,可以一次獲取一組元素(值)
print(s.loc["a"])
'''
c 1
d 2
dtype: int64
'''
# 也可以沿著索引層次進行訪問。
print(s.loc["a", "d"]) # 訪問指定坐標的元素值
'''
2
'''
# 通過位置索引訪問元素,與多層索引沒有任何關(guān)系。
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(標簽索引)操作,可以通過多層索引,獲取該索引所對應(yīng)的一組值。
- 通過iloc(位置索引)操作,會獲取對應(yīng)位置的一行(與是否多層索引無關(guān))。
- 通過s[操作]的行為有些詭異,建議不用。
- 對于索引,根據(jù)標簽獲取相應(yīng)的列(如果是多層索引,則可以獲得多列)。
- 對于數(shù)組索引, 根據(jù)標簽,獲取相應(yīng)的列(如果是多層索引,則可以獲得多列)。
- 對于切片,首先按照標簽進行索引,然后再按照位置進行索引(取行)。
#!/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("-----------指定行和列索引之后的數(shù)據(jù)值---------------")
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"]) # 對應(yīng)的外層索引的切片
'''
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"]) #取的是對應(yīng)的行數(shù)據(jù)
'''
x z 1
u 2
y z 3
u 4
'''
print('------df["x", "z"])--------')
print(df["x", "z"]) #取的是列數(shù)據(jù)
'''
a c 1
d 5
b c 9
d 13
Name: (x, z), dtype: int64
'''
# 通過位置訪問元素與是否多層索引無關(guān)。
print('----------df.iloc[0])-----------------')
print(df.iloc[0])
'''
x z 1
u 2
y z 3
u 4
Name: (a, c), dtype: int64
'''
交換索引
我們可以調(diào)用DataFrame對象的swaplevel方法來交換兩個層級索引。該方法默認對倒數(shù)第2層與倒數(shù)第1層進行交換。我們也可以指定交換的層。層次從0開始,由外向內(nèi)遞增(或者由上到下遞增),也可以指定負值,負值表示倒數(shù)第n層。除此之外,我們也可以使用層次索引的名稱來進行交換。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Time : 2019-06-13 13:07
# @Author : LiYahui
# @Description :
# 交換索引的層級,可以以一種不同的方式來進行展示(統(tǒng)計)。
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
'''
# 層級:從外層到內(nèi)層,值為0, 1, 2……,同時,層級也可以為負值,表示倒數(shù)第n個層級(由內(nèi)層到外層)。
# 例如,-1表示最內(nèi)層。
# 如果沒有顯式指定交換的層級,則默認交換最內(nèi)層的兩個層級。
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
'''
# 索引名字的作用。
# 除了數(shù)值來指定索引的層級外,我們也可以通過索引的名字來指定索引的層級。
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:指定根據(jù)哪一層進行排序,默認為最外(上)層。該值可以是數(shù)值,索引名,或者是由二者構(gòu)成的列表。
- 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參數(shù)指定索引的層級(排序的層級)。
# 如果沒有顯式指定,則默認為最外層的層級(層級為0)。
# 當我們對某個層級進行排序時,該層級的所有內(nèi)層層級也會進行排序。
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方法,可以進行索引堆疊,即將指定層級的列轉(zhuǎn)換成行。
- level:指定轉(zhuǎn)換的層級,默認為-1。
*詳見 Python--pandas--unstack() 與stack()
取消堆疊
- 通過DataFrame對象的unstack方法,可以取消索引堆疊,即將指定層級的行轉(zhuǎn)換成列。
- level:指定轉(zhuǎn)換的層級,默認為-1。
- fill_value:指定填充值。默認為NaN。
- 詳見: Python--pandas--unstack() 與stack()
設(shè)置索引
- 在DataFrame中,如果我們需要將現(xiàn)有的某一(幾)列作為索引列,可以調(diào)用set_index方法來實現(xiàn)。
- drop:是否丟棄作為新索引的列,默認為True。
- append:是否以追加的方式設(shè)置索引,默認為False。
- inplace:是否就地修改,默認為False。
- 詳見Python-pandas--set_index與reset_index
重置索引
- 調(diào)用在DataFrame對象的reset_index,可以重置索引。該操作與set_index正好相反。
- level:重置索引的層級,默認重置所有層級的索引。如果重置所有索引,將會創(chuàng)建默認整數(shù)序列索引。
- drop:是否丟棄重置的索引列,默認為False。
- inplace:是否就地修改,默認為False。
- 詳見 Python-pandas--set_index與reset_index