7.8 分層索引
譯者:飛龍
協(xié)議:CC BY-NC-SA 4.0
本節(jié)是《Python 數(shù)據(jù)科學(xué)手冊》(Python Data Science Handbook)的摘錄。
到目前為止祟敛,我們主要關(guān)注一維和二維數(shù)據(jù),分別存儲在 Pandas Series
和DataFrame
對象中锅睛。通常,超出此范圍并存儲更高維度的數(shù)據(jù)(即由多于一個(gè)或兩個(gè)鍵索引的數(shù)據(jù))是有用的印蔬。
雖然 Pandas 確實(shí)提供了Panel
和Panel4D
對象,這些對象原生地處理三維和四維數(shù)據(jù)(參見“旁注:面板數(shù)據(jù)”)退唠,實(shí)踐中的更常見模式是利用分層索引(也稱為多重索引)瞧预,在單個(gè)索引中合并多個(gè)索引層次盆驹。通過這種方式召娜,可以在熟悉的一維Series
和二維DataFrame
對象中,緊湊地表示高維數(shù)據(jù)雅倒。
在本節(jié)中蔑匣,我們將探索MultiIndex
對象的直接創(chuàng)建,在對多重索引數(shù)據(jù)執(zhí)行索引校套,切片和計(jì)算統(tǒng)計(jì)數(shù)據(jù)時(shí)的注意事項(xiàng)侨把,以及在數(shù)據(jù)的簡單和分層索引表示之間進(jìn)行轉(zhuǎn)換的有用例程秋柄。
我們以標(biāo)準(zhǔn)導(dǎo)入開始:
import pandas as pd
import numpy as np
多重索引的序列
讓我們首先考慮如何在一維Series
中表示二維數(shù)據(jù)。具體而言笨触,我們將考慮數(shù)據(jù)序列旭旭,其中每個(gè)點(diǎn)都有一個(gè)字符和數(shù)字鍵持寄。
不好的方式
假設(shè)你想跟蹤兩個(gè)不同年份的州的數(shù)據(jù)废麻。使用我們已經(jīng)介紹過的 Pandas 工具烛愧,你可能只想使用 Python 元組作為鍵:
index = [('California', 2000), ('California', 2010),
('New York', 2000), ('New York', 2010),
('Texas', 2000), ('Texas', 2010)]
populations = [33871648, 37253956,
18976457, 19378102,
20851820, 25145561]
pop = pd.Series(populations, index=index)
pop
'''
(California, 2000) 33871648
(California, 2010) 37253956
(New York, 2000) 18976457
(New York, 2010) 19378102
(Texas, 2000) 20851820
(Texas, 2010) 25145561
dtype: int64
'''
使用此索引方案,你可以根據(jù)這個(gè)多重索引沧卢,直接對序列索引或切片:
pop[('California', 2010):('Texas', 2000)]
'''
(California, 2010) 37253956
(New York, 2000) 18976457
(New York, 2010) 19378102
(Texas, 2000) 20851820
dtype: int64
'''
但也就這樣了。 例如立磁,如果你需要選擇 2010 年的所有值,則需要進(jìn)行一些混亂(并且可能很慢)的調(diào)整來實(shí)現(xiàn)它:
pop[[i for i in pop.index if i[1] == 2010]]
'''
(California, 2010) 37253956
(New York, 2010) 19378102
(Texas, 2010) 25145561
dtype: int64
'''
這會產(chǎn)生所需的結(jié)果才沧,但不像我們所喜歡的 Pandas 中的切片語法那樣干凈(或?qū)Υ笮蛿?shù)據(jù)集有效)。
更好的方式:Pandas MultiIndex
幸運(yùn)的是岁歉,Pandas 提供了一種更好的方式锅移。
我們的基于元組的索引非剃,本質(zhì)上是一個(gè)基本的多重索引备绽,而 Pandas 的MultiIndex
類型為我們提供了我們希望擁有的操作類型恨锚。我們可以從元組創(chuàng)建多重索引,如下所示:
index = pd.MultiIndex.from_tuples(index)
index
'''
MultiIndex(levels=[['California', 'New York', 'Texas'], [2000, 2010]],
labels=[[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1]])
'''
請注意他挎,MultiIndex
包含索引的多個(gè)層次 - 在這種情況下雇盖,州名稱和年份,以及編碼這些層次的狸相,每個(gè)數(shù)據(jù)點(diǎn)的多個(gè)標(biāo)簽。
如果我們用這個(gè)MultiIndex
重新索引我們的序列瘸右,我們會看到數(shù)據(jù)的分層表示:
pop = pop.reindex(index)
pop
'''
California 2000 33871648
2010 37253956
New York 2000 18976457
2010 19378102
Texas 2000 20851820
2010 25145561
dtype: int64
'''
這里Series
表示的前兩列展示了多個(gè)索引值,而第三列展示數(shù)據(jù)龄章。請注意,第一列中缺少某些條目:在多重索引表示中锚贱,任何空白條目都表示與其上方的行相同的值拧廊。
現(xiàn)在來訪問第二個(gè)索引是 2010 的所有數(shù)據(jù)耐量,我們可以簡單地使用 Pandas 切片表示法:
pop[:, 2010]
'''
California 37253956
New York 19378102
Texas 25145561
dtype: int64
'''
結(jié)果是一個(gè)單值索引的數(shù)組滤港,只帶有我們感興趣的鍵山叮。與我們開始使用的自制的基于元組的多重索引解決方案相比,這種語法更方便(并且操作更加高效!)钞翔。我們現(xiàn)在將進(jìn)一步討論分層索引數(shù)據(jù)上的這種索引操作布轿。
作為額外維度的MultiIndex
你可能會注意到其他內(nèi)容:我們可以使用帶有索引和列標(biāo)簽的簡單DataFrame
,來輕松存儲相同的數(shù)據(jù)来颤。事實(shí)上汰扭,Pandas 的構(gòu)建具有這種等價(jià)關(guān)系。 unstack()
方法會快速將多重索引的Series
轉(zhuǎn)換為常規(guī)索引的DataFrame
:
pop_df = pop.unstack()
pop_df
2000 | 2010 | |
---|---|---|
California | 33871648 | 37253956 |
New York | 18976457 | 19378102 |
Texas | 20851820 | 25145561 |
當(dāng)然福铅,stack()
方法提供了相反的操作:
pop_df.stack()
'''
California 2000 33871648
2010 37253956
New York 2000 18976457
2010 19378102
Texas 2000 20851820
2010 25145561
dtype: int64
'''
看到這個(gè)萝毛,你可能想知道為什么我們會糾結(jié)于分層索引。原因很簡單:就像我們能夠使用多重索引本讥,在一維序列中表示二維數(shù)據(jù)一樣,我們也可以用它在Series
或DataFrame
中表示更多維的數(shù)據(jù)。
多重索引中的每個(gè)額外層次表示數(shù)據(jù)的額外維度;利用這個(gè)屬性,我們可以更靈活地處理我們可以表示的數(shù)據(jù)類型巢寡。具體而言题诵,我們可能希望,每年為每個(gè)州添加另一列人口統(tǒng)計(jì)數(shù)據(jù)(例如钉赁,18 歲以下的人口); 使用MultiIndex
就像在DataFrame
中添加另一列一樣簡單:
pop_df = pd.DataFrame({'total': pop,
'under18': [9267089, 9284094,
4687374, 4318033,
5906301, 6879014]})
pop_df
total | under18 | ||
---|---|---|---|
California | 2000 | 33871648 | 9267089 |
2010 | 37253956 | 9284094 | |
New York | 2000 | 18976457 | 4687374 |
2010 | 19378102 | 4318033 | |
Texas | 2000 | 20851820 | 5906301 |
2010 | 25145561 | 6879014 |
此外式廷,“Pandas 中的數(shù)據(jù)操作”中討論的所有ufunc
和其他功能也適用于分層索引蠕趁。根據(jù)以上數(shù)據(jù)术浪,我們在這里按年計(jì)算 18 歲以下人口的比例:
f_u18 = pop_df['under18'] / pop_df['total']
f_u18.unstack()
2000 | 2010 | |
---|---|---|
California | 0.273594 | 0.249211 |
New York | 0.247010 | 0.222831 |
Texas | 0.283251 | 0.273568 |
這使我們能夠輕松快速地操作和探索高維數(shù)據(jù)倔毙。
MultiIndex
的創(chuàng)建方法
為Series
或DataFrame
構(gòu)造多重索引的最簡單方法诉儒,是簡單地將兩個(gè)或多個(gè)索引數(shù)組的列表傳遞給構(gòu)造器该互。 例如:
df = pd.DataFrame(np.random.rand(4, 2),
index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
columns=['data1', 'data2'])
df
data1 | data2 | ||
---|---|---|---|
a | 1 | 0.554233 | 0.356072 |
2 | 0.925244 | 0.219474 | |
b | 1 | 0.441759 | 0.610054 |
2 | 0.171495 | 0.886688 |
創(chuàng)建MultiIndex
的工作是在后臺完成的。
類似地萝嘁,如果你傳遞一個(gè)帶有適當(dāng)元組作為鍵的字典,Pandas 會自動識別它并默認(rèn)使用MultiIndex
:
data = {('California', 2000): 33871648,
('California', 2010): 37253956,
('Texas', 2000): 20851820,
('Texas', 2010): 25145561,
('New York', 2000): 18976457,
('New York', 2010): 19378102}
pd.Series(data)
'''
California 2000 33871648
2010 37253956
New York 2000 18976457
2010 19378102
Texas 2000 20851820
2010 25145561
dtype: int64
'''
然而河爹,顯式創(chuàng)建一個(gè)MultiIndex
有時(shí)很有用州丹;我們在這里會看到其中的幾種方法。
MultiIndex
顯式構(gòu)造器
為了更靈活地構(gòu)造索引眷唉,你可以使用pd.MultiIndex
中提供的類方法構(gòu)造器。例如,正如我們之前所做的那樣计济,你可以從一個(gè)簡單的數(shù)組列表中構(gòu)造MultiIndex
,提供每個(gè)層次中的索引值:
pd.MultiIndex.from_arrays([['a', 'a', 'b', 'b'], [1, 2, 1, 2]])
'''
MultiIndex(levels=[['a', 'b'], [1, 2]],
labels=[[0, 0, 1, 1], [0, 1, 0, 1]])
'''
你可以從元組列表構(gòu)造它燎含,提供每個(gè)點(diǎn)的多重索引值:
pd.MultiIndex.from_tuples([('a', 1), ('a', 2), ('b', 1), ('b', 2)])
'''
MultiIndex(levels=[['a', 'b'], [1, 2]],
labels=[[0, 0, 1, 1], [0, 1, 0, 1]])
'''
你甚至可以從單個(gè)索引的笛卡爾積中構(gòu)造它:
pd.MultiIndex.from_product([['a', 'b'], [1, 2]])
'''
MultiIndex(levels=[['a', 'b'], [1, 2]],
labels=[[0, 0, 1, 1], [0, 1, 0, 1]])
'''
類似地钝诚,你可以通過傳遞levels
(列表的列表泽铛,包含每個(gè)級別的可用索引值)和labels
(引用這些標(biāo)簽的列表的列表),直接使用其內(nèi)部編碼構(gòu)造MultiIndex
:
pd.MultiIndex(levels=[['a', 'b'], [1, 2]],
labels=[[0, 0, 1, 1], [0, 1, 0, 1]])
'''
MultiIndex(levels=[['a', 'b'], [1, 2]],
labels=[[0, 0, 1, 1], [0, 1, 0, 1]])
'''
當(dāng)創(chuàng)建Series
或Dataframe
時(shí),這些對象中的任何一個(gè)都可以作為index
參數(shù)傳遞凯亮,或者傳遞給現(xiàn)有Series
或DataFrame
的reindex
方法。
MultiIndex
層次名稱
有時(shí)命名MultiIndex
的層次很方便葵擎。
這可以通過將names
參數(shù)傳遞給上述任何一個(gè)MultiIndex
構(gòu)造器谅阿,或者通過在事后設(shè)置索引的names
屬性來實(shí)現(xiàn):
pop.index.names = ['state', 'year']
pop
'''
state year
California 2000 33871648
2010 37253956
New York 2000 18976457
2010 19378102
Texas 2000 20851820
2010 25145561
dtype: int64
'''
在更復(fù)雜數(shù)據(jù)集的情況下,這可能是跟蹤各種索引值含義的有用方法酬滤。
列的MultiIndex
在DataFrame
中签餐,行和列是完全對稱的,就像行可以有多個(gè)索引層次一樣盯串,列也可以有多個(gè)層次氯檐。考慮以下內(nèi)容体捏,這是一些(有些現(xiàn)實(shí)的)醫(yī)學(xué)數(shù)據(jù)的模型:
# 分層索引和列
index = pd.MultiIndex.from_product([[2013, 2014], [1, 2]],
names=['year', 'visit'])
columns = pd.MultiIndex.from_product([['Bob', 'Guido', 'Sue'], ['HR', 'Temp']],
names=['subject', 'type'])
# 生成一些數(shù)據(jù)
data = np.round(np.random.randn(4, 6), 1)
data[:, ::2] *= 10
data += 37
# 創(chuàng)建數(shù)據(jù)幀
health_data = pd.DataFrame(data, index=index, columns=columns)
health_data
| | subject | Bob | Guido | Sue |
| --- | --- | --- | --- | --- | --- | --- | --- |
| | type | HR | Temp | HR | Temp | HR | Temp |
| year | visit| | | | | | |
| 2013 | 1 | 31.0 | 38.7 | 32.0 | 36.7 | 35.0 | 37.2 |
| | 2 | 44.0 | 37.7 | 50.0 | 35.0 | 29.0 | 36.7 |
| 2014 | 1 | 30.0 | 37.4 | 39.0 | 37.8 | 61.0 | 36.9 |
| | 2 | 47.0 | 37.8 | 48.0 | 37.3 | 51.0 | 36.5 |
在這里冠摄,我們看到行和列的多重索引可以非常方便糯崎。這基本上是四維數(shù)據(jù),其中維度是受試者河泳,測量類型沃呢,年份和就診次數(shù)。有了這個(gè)拆挥,我們就可以通過人名來索引頂級列薄霜,并得到一個(gè)完整的DataFrame
,其中只包含該人的信息:
health_data['Guido']
type | HR | Temp | |
---|---|---|---|
year | visit | ||
2013 | 1 | 32.0 | 36.7 |
2 | 50.0 | 35.0 | |
2014 | 1 | 39.0 | 37.8 |
2 | 48.0 | 37.3 |
對于一些復(fù)雜記錄纸兔,它包含多個(gè)標(biāo)記的測量值惰瓜,并多次跨越許多受試者(人,國家食拜,城市等)鸵熟,使用分層的行和列非常方便副编!
MultiIndex
的索引和切片
MultiIndex
上的索引和切片設(shè)計(jì)得很直觀负甸,如果你將索引視為添加的維度,它會有所幫助痹届。我們首先看一下多重索引的Series
的索引呻待,然后是多重索引的DataFrame
。
多重索引的序列
考慮一下我們之前看到的队腐,州人口的多重索引的序列:
pop
'''
state year
California 2000 33871648
2010 37253956
New York 2000 18976457
2010 19378102
Texas 2000 20851820
2010 25145561
dtype: int64
'''
我們可以通過索引多項(xiàng)來訪問單個(gè)元素:
pop['California', 2000]
# 33871648
MultiIndex
也支持部分索引蚕捉,或僅索引索引中的一個(gè)層次。結(jié)果是另一個(gè)Series
柴淘,持有較低層次的索引:
pop['California']
'''
year
2000 33871648
2010 37253956
dtype: int64
'''
MultiIndex
是有序的迫淹,就可以執(zhí)行部分切片(參見“排序和未排序索引”中的討論):
pop.loc['California':'New York']
'''
state year
California 2000 33871648
2010 37253956
New York 2000 18976457
2010 19378102
dtype: int64
'''
對于有序索引,可以通過在第一個(gè)索引中傳遞空切片为严,來在較低層次上執(zhí)行部分索引:
pop[:, 2000]
'''
state
California 33871648
New York 18976457
Texas 20851820
dtype: int64
'''
其他類型的索引和選擇(在“數(shù)據(jù)索引和選擇”中討論)也可以使用敛熬;例如,基于布爾掩碼的選擇:
pop[pop > 22000000]
'''
state year
California 2000 33871648
2010 37253956
Texas 2010 25145561
dtype: int64
'''
基于花式索引的選擇也有效:
pop[['California', 'Texas']]
'''
state year
California 2000 33871648
2010 37253956
Texas 2000 20851820
2010 25145561
dtype: int64
'''
多重索引數(shù)據(jù)幀
多重索引的DataFrame
的表現(xiàn)類似第股∮γ瘢考慮我們之前的玩具醫(yī)療DataFrame
:
health_data
| | subject | Bob | Guido | Sue |
| --- | --- | --- | --- | --- | --- | --- | --- |
| | type | HR | Temp | HR | Temp | HR | Temp |
| year | visit| | | | | | |
| 2013 | 1 | 31.0 | 38.7 | 32.0 | 36.7 | 35.0 | 37.2 |
| | 2 | 44.0 | 37.7 | 50.0 | 35.0 | 29.0 | 36.7 |
| 2014 | 1 | 30.0 | 37.4 | 39.0 | 37.8 | 61.0 | 36.9 |
| | 2 | 47.0 | 37.8 | 48.0 | 37.3 | 51.0 | 36.5 |
請記住,列在DataFrame
中是主要的夕吻,并且用于多重索引的Series
的語法適用于列诲锹。例如,我們可以通過簡單的操作恢復(fù) Guido 的心率數(shù)據(jù):
health_data['Guido', 'HR']
'''
year visit
2013 1 32.0
2 50.0
2014 1 39.0
2 48.0
Name: (Guido, HR), dtype: float64
'''
此外涉馅,與單值索引情況一樣归园,我們可以使用“數(shù)據(jù)索引和選擇”中介紹的loc
,iloc
和ix
索引器稚矿。例如:
health_data.iloc[:2, :2]
| | subject | Bob |
| --- | --- | --- | --- |
| | type | HR | Temp |
| year | visit| | |
| 2013 | 1 | 31.0 | 38.7 |
| | 2 | 44.0 | 37.7 |
這些索引器提供了底層二維數(shù)據(jù)的數(shù)組式的視圖庸诱,但是可以向loc
或iloc
中的每個(gè)索引器悬钳,傳遞多個(gè)索引的元組。例如:
health_data.loc[:, ('Bob', 'HR')]
'''
year visit
2013 1 31.0
2 44.0
2014 1 30.0
2 47.0
Name: (Bob, HR), dtype: float64
'''
在這些索引元組中使用切片并不是特別方便偶翅;嘗試在元組中創(chuàng)建切片將導(dǎo)致語法錯(cuò)誤:
health_data.loc[(:, 1), (:, 'HR')]
'''
File "<ipython-input-32-8e3cc151e316>", line 1
health_data.loc[(:, 1), (:, 'HR')]
^
SyntaxError: invalid syntax
'''
你可以通過使用 Python 的內(nèi)置slice()
函數(shù)默勾,顯式構(gòu)建所需的切片,來解決這個(gè)問題聚谁,但在這種情況下母剥,更好的方法是使用IndexSlice
對象,正是由 Pandas 為這種情況提供的形导。
例如:
idx = pd.IndexSlice
health_data.loc[idx[:, 1], idx[:, 'HR']]
subject | Bob | Guido | Sue | |
---|---|---|---|---|
type | HR | HR | HR | |
year | visit | |||
2013 | 1 | 31.0 | 32.0 | 35.0 |
2014 | 1 | 30.0 | 39.0 | 61.0 |
有很多方法可以在多重索引的Series
和``DataFrame`中與數(shù)據(jù)進(jìn)行交互环疼,就像本書中的許多工具一樣,熟悉它們的最好方法就是嘗試它們朵耕!
重排多重索引
處理多重索引數(shù)據(jù)的關(guān)鍵之一炫隶,是知道如何有效地轉(zhuǎn)換數(shù)據(jù)。有許多操作將保留數(shù)據(jù)集中的所有信息阎曹,但為了各種計(jì)算的目的重新排列它伪阶。
我們在stack()
和unstack()
方法中看到了一個(gè)簡短的例子,但是還有很多方法处嫌,可以精確控制分層索引和列之間的數(shù)據(jù)重排栅贴,在這里我們將探索他們。
排序和未排序索引
早些時(shí)候熏迹,我們簡要地提到了一個(gè)警告檐薯,但我們應(yīng)該在這里強(qiáng)調(diào)一下。如果索引未排序注暗,多數(shù)MultiIndex
切片操作將失敗坛缕。在這里我們來看看。
我們首先創(chuàng)建一些簡單的多重索引數(shù)據(jù)捆昏,其中索引不是按字母順序排序:
index = pd.MultiIndex.from_product([['a', 'c', 'b'], [1, 2]])
data = pd.Series(np.random.rand(6), index=index)
data.index.names = ['char', 'int']
data
'''
char int
a 1 0.003001
2 0.164974
c 1 0.741650
2 0.569264
b 1 0.001693
2 0.526226
dtype: float64
'''
如果我們嘗試對此索引進(jìn)行部分切片赚楚,則會導(dǎo)致錯(cuò)誤:
try:
data['a':'b']
except KeyError as e:
print(type(e))
print(e)
'''
<class 'KeyError'>
'Key length (1) was greater than MultiIndex lexsort depth (0)'
'''
雖然從錯(cuò)誤消息中并不完全清楚,但這是MultiIndex
未排序的結(jié)果屡立。由于各種原因直晨,部分切片和其他類似操作要求MultiIndex
中的層次是(按字母順序)排序的。
Pandas 提供了許多便利的例程來執(zhí)行這種排序膨俐;例如DataFrame
的sort_index()
和sortlevel()
方法勇皇。我們這里將使用最簡單的sort_index()
:
data = data.sort_index()
data
'''
char int
a 1 0.003001
2 0.164974
b 1 0.001693
2 0.526226
c 1 0.741650
2 0.569264
dtype: float64
'''
通過以這種方式排序索引,部分切片將按預(yù)期工作:
data['a':'b']
'''
char int
a 1 0.003001
2 0.164974
b 1 0.001693
2 0.526226
dtype: float64
'''
索引堆疊和解除堆疊
正如我們之前簡要介紹的那樣焚刺,可以將數(shù)據(jù)集從堆疊的多索引轉(zhuǎn)換為簡單的二維表示敛摘,可選擇指定要使用的層次:
pop.unstack(level=0)
state | California | New York | Texas |
---|---|---|---|
year | |||
2000 | 33871648 | 18976457 | 20851820 |
2010 | 37253956 | 19378102 | 25145561 |
pop.unstack(level=1)
year | 2000 | 2010 |
---|---|---|
state | ||
California | 33871648 | 37253956 |
New York | 18976457 | 19378102 |
Texas | 20851820 | 25145561 |
unstack()
的反面是stack()
,這里可以用來恢復(fù)原始序列:
pop.unstack().stack()
'''
state year
California 2000 33871648
2010 37253956
New York 2000 18976457
2010 19378102
Texas 2000 20851820
2010 25145561
dtype: int64
'''
索引設(shè)置和重設(shè)
重排分層數(shù)據(jù)的另一種方法是將索引標(biāo)簽轉(zhuǎn)換為列乳愉;這可以通過reset_index
方法完成兄淫。
在人口字典上調(diào)用它將產(chǎn)生一個(gè)帶有state
和year
列的DataFrame
屯远,包含以前在索引中的信息。
為清楚起見捕虽,我們可以為列表示指定數(shù)據(jù)名稱:
pop_flat = pop.reset_index(name='population')
pop_flat
state | year | population | |
---|---|---|---|
0 | California | 2000 | 33871648 |
1 | California | 2010 | 37253956 |
2 | New York | 2000 | 18976457 |
3 | New York | 2010 | 19378102 |
4 | Texas | 2000 | 20851820 |
5 | Texas | 2010 | 25145561 |
通常處理現(xiàn)實(shí)世界中的數(shù)據(jù)時(shí)慨丐,原始輸入數(shù)據(jù)看起來像這樣,從列值構(gòu)建MultiIndex
會有用泄私。這可以通過DataFrame
的set_index
方法完成房揭,它返回一個(gè)多重索引的DataFrame
:
pop_flat.set_index(['state', 'year'])
population | |||
---|---|---|---|
state | year | ||
California | 2000 | 33871648 | |
2010 | 37253956 | ||
New York | 2000 | 18976457 | |
2010 | 19378102 | ||
Texas | 2000 | 20851820 | |
2010 | 25145561 |
在實(shí)踐中,遇到真實(shí)數(shù)據(jù)集時(shí)晌端,我發(fā)現(xiàn)這種類型的重索引捅暴,是更有用的模式之一。
多重索引上的數(shù)據(jù)聚合
我們以前看到咧纠,Pandas 有內(nèi)置的數(shù)據(jù)聚合方法蓬痒,比如mean()``,
sum()和
max()漆羔。對于分層索引數(shù)據(jù)梧奢,可以傳遞
level``參數(shù),該參數(shù)控制聚合在上面計(jì)算的數(shù)據(jù)子集钧椰。
例如粹断,讓我們回到我們的健康數(shù)據(jù):
health_data
| | subject | Bob | Guido | Sue |
| --- | --- | --- | --- | --- | --- | --- | --- |
| | type | HR | Temp | HR | Temp | HR | Temp |
| year | visit| | | | | | |
| 2013 | 1 | 31.0 | 38.7 | 32.0 | 36.7 | 35.0 | 37.2 |
| | 2 | 44.0 | 37.7 | 50.0 | 35.0 | 29.0 | 36.7 |
| 2014 | 1 | 30.0 | 37.4 | 39.0 | 37.8 | 61.0 | 36.9 |
| | 2 | 47.0 | 37.8 | 48.0 | 37.3 | 51.0 | 36.5 |
也許我們想對每年的兩次就診的測量值求平均。 我們可以通過指定我們想要探索的索引層次來實(shí)現(xiàn)嫡霞,在這種情況下是年份:
data_mean = health_data.mean(level='year')
data_mean
| subject | Bob | Guido | Sue |
| --- | --- | --- | --- | --- | --- | --- |
| type | HR | Temp | HR | Temp | HR | Temp |
| year| | | | | | |
| 2013 | 37.5 | 38.2 | 41.0 | 35.85 | 32.0 | 36.95 |
| 2014 | 38.5 | 37.6 | 43.5 | 37.55 | 56.0 | 36.70 |
通過進(jìn)一步利用axis
關(guān)鍵字,我們可以在列上的層次中取平均值:
data_mean.mean(axis=1, level='type')
type | HR | Temp |
---|---|---|
year | ||
2013 | 36.833333 | 37.000000 |
2014 | 46.000000 | 37.283333 |
因此希柿,在兩行中诊沪,我們已經(jīng)能夠查詢每年所有就診和所有受試者的平均心率和體溫。這個(gè)語法實(shí)際上是GroupBy
函數(shù)的簡寫曾撤,我們將在“聚合和分組”中討論端姚。雖然這是一個(gè)玩具示例,但許多真實(shí)世界的數(shù)據(jù)集具有相似的層次結(jié)構(gòu)挤悉。
旁注:面板數(shù)據(jù)
Pandas 還有一些我們尚未討論的基本數(shù)據(jù)結(jié)構(gòu)渐裸,即pd.Panel
和pd.Panel4D
對象。這些可以分別認(rèn)為是(一維)Series
和(二維)DataFrame
結(jié)構(gòu)的三維和四維擴(kuò)展装悲。
一旦熟悉了Series
和DataFrame
中的數(shù)據(jù)索引和操作昏鹃,Panel
和Panel4D
就相對簡單易用了。特別是诀诊,“數(shù)據(jù)索引和選擇”中討論的ix
洞渤,loc
和iloc
索引器,很容易擴(kuò)展到這些更高維的結(jié)構(gòu)属瓣。
我們將不會在本文中進(jìn)一步介紹這些面板結(jié)構(gòu)载迄,因?yàn)槲以诖蠖鄶?shù)情況下發(fā)現(xiàn)讯柔,對于更高維數(shù)據(jù)來說,多重索引是更有用且概念上更簡單的表示护昧。另外魂迄,面板數(shù)據(jù)基本上是密集數(shù)據(jù)表示,而多索引基本上是稀疏數(shù)據(jù)表示惋耙。
隨著維度數(shù)量的增加极祸,對于大多數(shù)真實(shí)世界的數(shù)據(jù)集,密集表示可能變得非常低效怠晴。然而遥金,對于特定場合下的應(yīng)用,這些結(jié)構(gòu)可能是有用的蒜田。如果你想了解Panel
和Panel4D
結(jié)構(gòu)的更多信息稿械,請參考“更多資源”中列出的參考資料。