索引(index)是 Pandas 的重要工具,通過索引可以從 DataFame 中選擇特定的行數和列數,這種選擇數據的方式稱為“子集選擇”。
在 Pandas 中,索引值也被稱為標簽(label),它在 Jupyter 筆記本中以粗體字進行顯示。索引可以加快數據訪問的速度,它就好比數據的書簽,通過它可以實現數據的快速查找。
創建索引
通過示例對 index 索引做進一步講解。下面創建一個帶有 index 索引的數據,並使用 read_csv() 這些讀取數據:
- import pandas as pd
- data = pd.read_csv("person.csv")
- print(data)
輸出結果:
ID Name Age City Salary 0 1 Jack 28 Beijing 22000 1 2 Lida 32 Shanghai 19000 2 3 John 43 Shenzhen 12000 3 4 Helen 38 Hengshui 3500
通過列索引(標簽)讀取多列數據。
- import pandas as pd
- #設置"Name"為行索引
- data = pd.read_csv("person.csv", index_col ="Name")
- # 通過列標簽選取多列數據
- a = data[["City","Salary"]]
- print(a)
輸出結果:
City Salary Name Jack Beijing 22000 Lida Shanghai 19000 John Shenzhen 12000 Helen Hengshui 3500
再看一組簡單的示例:
- import pandas as pd
- info =pd.read_csv("person.csv", index_col ="Name")
- #獲取單列數據,或者以列表的形式傳入["Salary"]
- a =info["Salary"]
- print(a)
輸出結果:
Salary Name Jack 22000 Lida 19000 John 12000 Helen 3500
設置索引
set_index() 將已存在的列標簽設置為 DataFrame 行索引。除了可以添加索引外,也可以替換已經存在的索引。比如您也可以把 Series 或者一個 DataFrme 設置成另一個 DataFrame 的索引。示例如下:
- info = pd.DataFrame({'Name': ['Parker', 'Terry', 'Smith', 'William'], 'Year': [2011, 2009, 2014, 2010],
- 'Leaves': [10, 15, 9, 4]})
- #設置Name為行索引
- print(info.set_index('Name'))
輸出結果:
Year Leaves Name Parker 2011 10 Terry 2009 15 Smith 2014 9 William 2010 4
重置索引
您可以使用 reset_index() 來恢復初始行索引,示例如下:
- import pandas as pd
- import numpy as np
- info = pd.DataFrame([('William', 'C'),
- ('Smith', 'Java'),
- ('Parker', 'Python'),
- ('Phill', np.nan)],
- index=[1, 2, 3, 4],
- columns=('name', 'Language'))
- print(info)
- print(info.reset_index())
輸出結果:
重置前: name Language 1 William C 2 Smith Java 3 Parker Python 4 Phill NaN 重置后: index name Language 0 1 William C 1 2 Smith Java 2 3 Parker Python 3 4 Phill NaN
---------------------------------------------------------------------------------------
分層索引(Multiple Index)是 Pandas 中非常重要的索引類型,它指的是在一個軸上擁有多個(即兩個以上)索引層數,這使得我們可以用低維度的結構來處理更高維的數據。比如,當想要處理三維及以上的高維數據時,就需要用到分層索引。
分層索引的目的是用低維度的結構(Series 或者 DataFrame)更好地處理高維數據。通過分層索引,我們可以像處理二維數據一樣,處理三維及以上的數據。分層索引的存在使得分析高維數據變得簡單,讓抽象的高維數據變得容易理解,同時它比廢棄的 Panel 結構更容易使用。
Pandas 可以通過 MultiIndex() 方法來創建分層索引對象,該對象本質上是一個元組序列,序列中每一個元組都是唯一的。下面介紹幾種創建分層索引的方式。
創建分層索引
1) 直接創建
通過 MultiIndex() 的levels
參數能夠直接創建分層索引,示例如下:
- import pandas as pd
- import numpy as np
- #為leves傳遞一個1行5列的二維數組
- df=pd.MultiIndex(levels=[[np.nan, 2, pd.NaT, None, 5]], codes=[[4, -1, 1, 2, 3, 4]])
- print(df.levels)
- print(df)
輸出結果:
[[nan, 2, NaT, None, 5]] MultiIndex([( 5,), (nan,), ( 2,), (nan,), (nan,), ( 5,)], )
上述代碼中,levels
參數用來創建層級索引,這里只有一層,該層的索引值分別是 np.nan, 2, NaT, None, 5;codes
表示按參數值對層級索引值排序(與 levels 中的值相對應),也就說 codes 中數值是 leves 序列的下標索引。需要注意,這里的 -1 代表 NaN。
2) 從元組創建
通過 from_tuples() 實現從元組創建分層索引。
- #創建元組序列
- arrays = [['it', 'it', 'of', 'of', 'for', 'for', 'then', 'then'],
- ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']]
- #使用zip()函數創建元組
- tuples = list(zip(*arrays))
- print(tuples)
輸出結果如下:
[('it', 'one'), ('it', 'two'), ('of', 'one'), ('of', 'two'), ('for', 'one'), ('for', 'two'), ('then', 'one'), ('then', 'two')]
然后使用 tuples 創建分層索引,如下所示:
- import pandas as pd
- #創建了兩層索引,並使用names對它們命名
- index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
- print(index)
輸出結果:
MultiIndex([( 'it', 'one'), ( 'it', 'two'), ( 'of', 'one'), ( 'of', 'two'), ( 'for', 'one'), ( 'for', 'two'), ('then', 'one'), ('then', 'two')], names=['first', 'second'])
3) 從DataFrame對象創建
通過 from_frame() 創建分層索引,示例如下:
- #首先創建一個 DataFrame。
- import pandas as pd
- df = pd.DataFrame([['bar', 'one'], ['bar', 'two'],
- ['foo', 'one'], ['foo', 'two']],
- columns=['first', 'second'])
- #然后使用 from_frame()創建分層索引。
- index = pd.MultiIndex.from_frame(df)
- #將index應用於Series
- s=pd.Series(np.random.randn(4), index=index)
- print(s)
輸出結果:
first second bar one 1.151928 two -0.694435 foo one -1.701611 two -0.486157 dtype: float64
4) 笛卡爾積創建
笛卡爾積(又稱直積)是數學運算的一種方式,下面使用 from_product() 笛卡爾積創建分層索引。
- import pandas as pd
- #構建數據
- numbers = [0, 1, 2]
- language = ['Python', 'Java']
- #經過笛卡爾積處理后會得到6中組合方式
- index = pd.MultiIndex.from_product([numbers, language],names=['number', 'language'])
- #將分層索引對象應用於Series
- dk_er=pd.Series(np.random.randn(6), index=index)
- print(dk_er)
輸出結果:
number language 0 Python -0.319739 Java 1.599170 1 Python -0.010520 Java 0.262068 2 Python -0.124177 Java 0.315120 dtype: float64
5) 數組創建分層索引
通過 from_array() 方法,同樣可以創建分層索引。示例如下:
- import pandas as pd
- df=pd.MultiIndex.from_arrays([['a', 'a', 'b', 'b'],[1, 2, 1, 2]])
- df
輸出結果:
MultiIndex([('a', 1), ('a', 2), ('b', 1), ('b', 2)], )
應用分層索引
下面示例講解了如何在 DataFrame 中應用分層索引。
- import pandas as pd
- import numpy as np
- #創建一個數組
- arrays = [[0, 0, 1, 1], ['A', 'B', 'A', 'B']]
- #從數組創建
- index=pd.MultiIndex.from_arrays(arrays, names=('number', 'letter'))
- print(index)
輸出結果
MultiIndex([(0, 'A'), (0, 'B'), (1, 'A'), (1, 'B')], names=['number', 'letter'])
上述示例中,第一層為 number,該層有 0、1 兩個元素,第二層為 letter,有兩個字母 A 和 B。
下面把已經創建的分層索引應用到 DataFrame 中,如下所示:
- import pandas as pd
- import numpy as np
- #創建一個數組
- arrays = [[0, 0, 1, 1], ['A', 'B', 'A', 'B']]
- index=pd.MultiIndex.from_arrays(arrays, names=('number', 'letter'))
- #在行索引位置應用分層索引
- df=pd.DataFrame([{'a':11, 'b':22}], index=index)
- print(df)
輸出結果:
a b number letter 0 A 11 22 B 11 22 1 A 11 22 B 11 22
通過 set_index() 可以將 DataFrame 的已有列的標索設置為 index 行索引,示例如下:
- import pandas as pd
- df= pd.DataFrame({'a': range(5), 'b': range(5, 0, -1),
- 'c': ['one', 'one', 'one', 'two', 'two'],
- 'd': [0, 1, 2, 0, 1]})
- print(df)
- df1=df.set_index(['a','d'],drop=False)
- print(df1)
- df1=df.set_index(['a','d'],drop=False,append=Ture)
- print(df2)
輸出結果:
轉換前: a b c d 0 0 5 one 0 1 1 4 one 1 2 2 3 one 2 3 3 2 two 0 4 4 1 two 1 轉換后: a b c d a d 0 0 0 5 one 0 1 1 1 4 one 1 2 2 2 3 one 2 3 0 3 2 two 0 4 1 4 1 two 1 帶append參數: a b c d a d 0 0 0 0 5 one 0 1 1 1 1 4 one 1 2 2 2 2 3 one 2 3 3 0 3 2 two 0 4 4 1 4 1 two 1
通過 set_index() 將列索引轉換為了分層行索引,其中 drop=False 表示更新索引的同時,不刪除 a、d 列;同時,該函數還提供了一個 append = Ture 參數表示不添加默認的整數索引值(0到4)
分層索引切片取值
下面講解分層索引切片取值操作,示例如下:
1) 分層行索引操作
- import pandas as pd
- #構建多層索引
- tuple = [('湖人',2008),('步行者',2008),
- ('湖人',2007),('凱爾特人',2007),
- ('籃網',2007),('熱火',2008)]
- salary = [10000,20000,11000,30000,19000,22000]
- #其次應用於DataFrame
- index = pd.MultiIndex.from_tuples(tuple)
- s = pd.Series(salary, index=index)
- print(s)
- #切片取值
- print(s['湖人',2007])
- print(s['湖人'])
- print(s[:,2008])
- #比較value
- print(s[s<=20000])
輸出結果:
湖人 2008 10000 步行者 2008 20000 湖人 2007 11000 凱爾特人 2007 30000 籃網 2007 19000 熱火 2008 22000 dtype: int64 湖人隊2007年工資: 11000 湖人隊的工資: 2008 10000 2007 11000 dtype: int64 2008年所有隊伍工資: 湖人 10000 步行者 20000 熱火 22000 dtype: int64 小於等於20000的年份和隊伍: 湖人 2008 10000 步行者 2008 20000 湖人 2007 11000 籃網 2007 19000 dtype: int64
2) 行、列多層索引操作
下面看一種更加復雜的情況,就是行、列同時存在多層索引時候,應該如何通過切片取值。示例如下:
- df = pd.DataFrame(np.arange(1,13).reshape((4, 3)),
- index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
- columns=[['Jack', 'Jack', 'Helen'],
- ['Python', 'Java', 'Python']])
- #選擇同一層級的索引,切記不要寫成['Jack','Helen']
- print(df[['Jack','Helen']])
- #在不同層級分別選擇索引
- print(df['Jack','Python'])
- #iloc整數索引
- print(df.iloc[:3,:2])
- #loc列標簽索引
- print(df.loc[:,('Helen','Python')])
輸出結果:
Jack Helen Python Java Python a 1 1 2 3 2 4 5 6 b 1 7 8 9 2 10 11 12 a 1 1 2 4 b 1 7 2 10 Name: (Jack, Python), dtype: int32 Jack Python Java a 1 1 2 2 4 5 b 1 7 8 a 1 3 2 6 b 1 9 2 12 Name: (Helen, Python), dtype: int32
聚合函數應用
通過給level
傳遞參數值,您可以指定在哪個層上進行聚合操作,比如求和、求均值等。示例如下:
- import pandas as pd
- df = pd.DataFrame(np.arange(1,13).reshape((4, 3)),
- index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
- columns=[['Jack', 'Jack', 'Helen'],
- ['Python', 'Java', 'Python']])
- #第一步,給行列層級起名字
- df.index.names=['key1','key2']
- df.columns.names=['name','course']
- print(df.sum(level='key2'))
- print(df.mean(level="course",axis=1))
輸出結果:
#對key2層1/2對應的元素值求和 name Jack Helen course Python Java Python key2 1 8 10 12 2 14 16 18 #axis=1沿着水平方向求均值 course Python Java key1 key2 a 1 2 2 2 5 5 b 1 8 8 2 11 11
在數據分析的過程中,我們把大部分時間都花費在數據的准備和預處理上,Pandas 作為一個靈活、高效的數據預處理工具,提供了諸多數據處理的方法,分層索引(Multiple Index)就是其中之一,分層索引(或多層索引)是 Pandas 的基本特性,它能夠增強 Pands 數據預處理的能力。
對於 Series 結構來說,通過給index
參數傳遞一個二維數組就可以創建一個具有兩層索引的 MultiIndex 對象,示例如下:
- import pandas as pd
- info = pd.Series([11, 14, 17, 24, 19, 32, 34, 27],
- index = [['x', 'x', 'x', 'x', 'y', 'y', 'y', 'y'],
- ['obj1', 'obj2', 'obj3', 'obj4', 'obj1', 'obj2', 'obj3', 'obj4']])
- print(info)
輸出結果:
x obj1 11 obj2 14 obj3 17 obj4 24 y obj1 19 obj2 32 obj3 34 obj4 27 dtype: int64
上述示例,創建了兩個層級的索引,即 (x, y) 和 (obj1,…, obj4),您可以使用 'index' 命令查看索引。
info.index
輸出結果:
MultiIndex([('x', 'obj1'), ('x', 'obj2'), ('x', 'obj3'), ('x', 'obj4'), ('y', 'obj1'), ('y', 'obj2'), ('y', 'obj3'), ('y', 'obj4')], )
此外,您還可以基於內部索引層(也就是'obj')來選擇數據。如下所示:
info [:,'obj2' ]
輸出結果:
x 14 y 32 dtype: int64
局部索引
局部索引可以理解為:從分層索引中選擇特定索引層的一種方法。比如在下列數據中,選擇所有'y'
索引指定的數據,示例如下:
- import pandas as pd
- info = pd.Series([11, 14, 17, 24, 19, 32, 34, 27],
- index = [['x', 'x', 'x', 'x', 'y', 'y', 'y', 'y'],
- ['obj1', 'obj2', 'obj3', 'obj4', 'obj1', 'obj2', 'obj3', 'obj4']])
- info['y']
輸出結果:
obj1 19 obj2 32 obj3 34 obj4 27 dtype: int64
當然您也可以基於內層索引選擇數據。
行索引層轉換為列索引
unstack() 用來將行索引轉變成列索引,相當於轉置操作。通過 unstack() 可以將 Series(一維序列)轉變為 DataFrame(二維序列)。示例如下:
- import pandas as pd
- info = pd.Series([11, 14, 17, 24, 19, 32, 34, 27],
- index = [['x', 'x', 'x', 'x', 'y', 'y', 'y', 'y'],
- ['obj1', 'obj2', 'obj3', 'obj4', 'obj1', 'obj2', 'obj3', 'obj4']])
- #行索引標簽默認是最外層的 x, y
- #0代表第一層索引,而1代表第二層
- print(info.unstack(0))
輸出結果:
- x y
- obj1 11 19
- obj2 14 32
- obj3 17 34
- obj4 24 27
從示例可以看出,unstack(0) 表示選擇第一層索引作為列,unstack(1) 表示選擇第二層,如下所示:
- import pandas as pd
- info = pd.Series([11, 14, 17, 24, 19, 32, 34, 27],
- index = [['x', 'x', 'x', 'x', 'y', 'y', 'y', 'y'],
- ['obj1', 'obj2', 'obj3', 'obj4', 'obj1', 'obj2', 'obj3', 'obj4']])
- print(info.unstack(1))
輸出結果:
obj1 obj2 obj3 obj4 x 11 14 17 24 y 19 32 34 27
列索引實現分層
我們知道,列索引存在於 DataFrame 結構中,下面創建一個 DataFrame 來演示列索引如何實現分層。
- import numpy as np
- info = pd.DataFrame(np.arange(12).reshape(4, 3),
- index = [['a', 'a', 'b', 'b'], ['one', 'two', 'three', 'four']],
- columns = [['num1', 'num2', 'num3'], ['x', 'y', 'x']] )
- print(info)
輸出結果:
num1 num2 num3 x y x a one 0 1 2 two 3 4 5 b three 6 7 8 four 9 10 11
查看所有列索引:
info.columns
輸出結果:
MultiIndex([('num1', 'x'), ('num2', 'y'), ('num3', 'x')],)
交換層和層排序
1) 交換層
通過 swaplevel() 方法輕松地實現索引層交換,示例如下:
- import pandas as pd
- frame = pd.DataFrame(np.arange(12).reshape((4, 3)),
- index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
- columns=[['Ohio', 'Ohio', 'Colorado'],
- ['Green', 'Red', 'Green']])
- #設置index的levels名稱
- frame.index.names = ['key1', 'key2']
- #設置columns的levels名稱
- frame.columns.names = ['state','color']
- #交換key1層與key層
- frame.swaplevel('key1','key2')
輸出結果:
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
2) 層排序
通過 sort_index() 的level
參數實現對層的排序。下面示例,按“key1”的字母順序重新排序。
- import pandas as pd
- frame = pd.DataFrame(np.arange(12).reshape((4, 3)),
- index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
- columns=[['Ohio', 'Ohio', 'Colorado'],
- ['Green', 'Red', 'Green']])
- #設置index的levels的名稱,key1 與 key2分別對應不同的層
- frame.index.names = ['key1', 'key2']
- #設置columns的levels的名稱
- frame.columns.names = ['state','color']
- print(frame.sort_index(level='key1'))
輸出結果:
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