最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Pandas 分層索引的具體實(shí)踐

 更新時(shí)間:2025年11月04日 09:23:29   作者:Humbunklung  
本筆記系統(tǒng)介紹了 Pandas 的分層索引及其在 Series 和 DataFrame 中的應(yīng)用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

Pandas 分層索引

到目前為止,我們主要關(guān)注的是一維和二維數(shù)據(jù),分別存儲在 Pandas 的 SeriesDataFrame 對象中。但很多時(shí)候,存儲更高維度的數(shù)據(jù)——即由多個(gè)鍵索引的數(shù)據(jù)——是很有用的。
早期的 Pandas 版本提供了 PanelPanel4D 對象,可以被視為二維 DataFrame 的三維或四維類似物,但在實(shí)際使用中它們有些笨重。處理高維數(shù)據(jù)更常見的模式是利用分層索引(也稱為多重索引),在單個(gè)索引中包含多個(gè)索引層級。通過這種方式,更高維度的數(shù)據(jù)可以緊湊地表示在熟悉的一維 Series 和二維 DataFrame 對象中。

(如果你對具有 Pandas 風(fēng)格靈活索引的真正N維數(shù)組感興趣,可以了解優(yōu)秀的 Xarray 包。)

在本章中,我們將探討 MultiIndex 對象的直接創(chuàng)建;在多重索引數(shù)據(jù)上進(jìn)行索引、切片和統(tǒng)計(jì)計(jì)算時(shí)的注意事項(xiàng);以及在簡單和分層索引數(shù)據(jù)表示之間轉(zhuǎn)換的實(shí)用方法。

我們從標(biāo)準(zhǔn)導(dǎo)入開始:

import pandas as pd
import numpy as np

多重索引的 Series

讓我們從思考如何在一維 Series 中表示二維數(shù)據(jù)開始。
為了具體說明,我們將考慮一個(gè)數(shù)據(jù)序列,其中每個(gè)數(shù)據(jù)點(diǎn)都有一個(gè)字符和一個(gè)數(shù)字鍵。

糟糕的方式

假設(shè)你想跟蹤兩個(gè)不同年份的各州數(shù)據(jù)。利用我們已經(jīng)介紹過的 Pandas 工具,你可能會傾向于直接使用 Python 元組作為鍵:

index = [('California', 2010), ('California', 2020),
         ('New York', 2010), ('New York', 2020),
         ('Texas', 2010), ('Texas', 2020)]
populations = [37253956, 39538223,
               19378102, 20201249,
               25145561, 29145505]
pop = pd.Series(populations, index=index)
pop
(California, 2010)    37253956
(California, 2020)    39538223
(New York, 2010)      19378102
(New York, 2020)      20201249
(Texas, 2010)         25145561
(Texas, 2020)         29145505
dtype: int64

使用這種索引方案,你可以直接根據(jù)元組索引對 Series 進(jìn)行索引或切片:

pop[('California', 2020):('Texas', 2010)]
(California, 2020)    39538223
(New York, 2010)      19378102
(New York, 2020)      20201249
(Texas, 2010)         25145561
dtype: int64

但便利也僅止于此。例如,如果你需要選擇所有 2010 年的數(shù)據(jù),你就需要進(jìn)行一些繁瑣(而且可能很慢)的數(shù)據(jù)處理才能實(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

這確實(shí)得到了想要的結(jié)果,但相比我們已經(jīng)習(xí)慣的 Pandas 切片語法,這種方式不夠簡潔(對于大型數(shù)據(jù)集來說也不夠高效)。

更好的方式:Pandas 的 MultiIndex

幸運(yùn)的是,Pandas 提供了更好的方法。
我們基于元組的索引本質(zhì)上就是一種初級的多重索引,而 Pandas 的 MultiIndex 類型為我們提供了所需的各種操作。
我們可以如下通過元組創(chuàng)建一個(gè)多重索引:

index = pd.MultiIndex.from_tuples(index)

MultiIndex 表示多個(gè)索引層級——在本例中為州名和年份——以及為每個(gè)數(shù)據(jù)點(diǎn)編碼這些層級的多個(gè)標(biāo)簽。

如果我們用這個(gè) MultiIndex 重新索引我們的 series,就可以看到數(shù)據(jù)的分層表示:

pop = pop.reindex(index)
pop
California  2010    37253956
            2020    39538223
New York    2010    19378102
            2020    20201249
Texas       2010    25145561
            2020    29145505
dtype: int64

在 Series 的表示中,前兩列顯示了多重索引的值,第三列顯示了數(shù)據(jù)。
請注意,第一列中有些條目是空白的:在這種多重索引的表示中,任何空白條目都表示與上一行相同的值。

現(xiàn)在,如果我們想訪問第二層索引為 2020 的所有數(shù)據(jù),可以使用 Pandas 的切片語法:

pop[:, 2020]
California    39538223
New York      20201249
Texas         29145505
dtype: int64

結(jié)果是一個(gè)只包含我們感興趣鍵的單層索引 Series。
這種語法比我們一開始用元組實(shí)現(xiàn)的多重索引方案要方便得多(操作效率也高得多)。
接下來我們將進(jìn)一步討論這種針對分層索引數(shù)據(jù)的索引操作。

多重索引作為額外的維度

你可能還注意到:我們其實(shí)可以用帶有索引和列標(biāo)簽的普通 DataFrame 來存儲相同的數(shù)據(jù)。
事實(shí)上,Pandas 的設(shè)計(jì)正是基于這種等價(jià)性。unstack 方法可以迅速將一個(gè)多重索引的 Series 轉(zhuǎn)換為常規(guī)索引的 DataFrame

pop_df = pop.unstack()
pop_df
20102020
California3725395639538223
New York1937810220201249
Texas2514556129145505

自然而然,stack 方法則提供了相反的操作:

pop_df.stack()
California  2010    37253956
            2020    39538223
New York    2010    19378102
            2020    20201249
Texas       2010    25145561
            2020    29145505
dtype: int64

看到這里,你可能會想,為什么我們還要費(fèi)心使用分層索引呢?
原因很簡單:正如我們能夠利用多重索引在一維的 Series 中操作二維數(shù)據(jù)一樣,我們也可以用它在 SeriesDataFrame 中操作三維或更多維度的數(shù)據(jù)。
多重索引中的每增加一個(gè)層級,就代表數(shù)據(jù)的一個(gè)額外維度;利用這一特性,我們可以更靈活地表示各種類型的數(shù)據(jù)。具體來說,我們可能希望為每個(gè)州的每一年添加另一列人口統(tǒng)計(jì)數(shù)據(jù)(比如 18 歲以下人口);有了 MultiIndex,只需在 DataFrame 中添加一列即可輕松實(shí)現(xiàn):

pop_df = pd.DataFrame({'total': pop,
                       'under18': [9284094, 8898092,
                                   4318033, 4181528,
                                   6879014, 7432474]})
pop_df
totalunder18
California2010372539569284094
2020395382238898092
New York2010193781024318033
2020202012494181528
Texas2010251455616879014
2020291455057432474

此外,Pandas中的數(shù)據(jù)操作中討論的所有 ufuncs 和其他功能同樣適用于分層索引。
下面我們根據(jù)上述數(shù)據(jù),按年份計(jì)算 18 歲以下人口所占比例:

f_u18 = pop_df['under18'] / pop_df['total']
f_u18.unstack()
20102020
California0.2492110.225050
New York0.2228310.206994
Texas0.2735680.255013

這使我們能夠輕松快速地操作和探索高維數(shù)據(jù)。

多重索引的創(chuàng)建方法

構(gòu)建多重索引的 SeriesDataFrame 最直接的方法,就是將兩個(gè)或更多索引數(shù)組的列表直接傳遞給構(gòu)造函數(shù)。例如:

df = pd.DataFrame(np.random.rand(4, 2),
                  index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
                  columns=['data1', 'data2'])
df
data1data2
a10.6268330.939326
20.8249480.823318
b10.9538310.173091
20.3713340.779618

創(chuàng)建 MultiIndex 的工作是在后臺完成的。

類似地,如果你傳遞一個(gè)以合適元組為鍵的字典,Pandas 會自動識別并默認(rèn)使用 MultiIndex

data = {('California', 2010): 37253956,
        ('California', 2020): 39538223,
        ('New York', 2010): 19378102,
        ('New York', 2020): 20201249,
        ('Texas', 2010): 25145561,
        ('Texas', 2020): 29145505}
pd.Series(data)
California  2010    37253956
            2020    39538223
New York    2010    19378102
            2020    20201249
Texas       2010    25145561
            2020    29145505
dtype: int64

盡管如此,有時(shí)顯式創(chuàng)建一個(gè) MultiIndex 也是很有用的;接下來我們將介紹幾種實(shí)現(xiàn)這一目標(biāo)的方法。

顯式 MultiIndex 構(gòu)造器

為了更靈活地構(gòu)建索引,你可以使用 pd.MultiIndex 類中提供的構(gòu)造方法。
例如,正如我們之前所做的,可以通過簡單的數(shù)組列表(每個(gè)層級的索引值)來構(gòu)造一個(gè) MultiIndex

pd.MultiIndex.from_arrays([['a', 'a', 'b', 'b'], [1, 2, 1, 2]])
MultiIndex([('a', 1),
            ('a', 2),
            ('b', 1),
            ('b', 2)],
           )

或者,你可以通過一個(gè)元組列表(每個(gè)元組給出每個(gè)數(shù)據(jù)點(diǎn)的多重索引值)來構(gòu)造它:

pd.MultiIndex.from_tuples([('a', 1), ('a', 2), ('b', 1), ('b', 2)])
MultiIndex([('a', 1),
            ('a', 2),
            ('b', 1),
            ('b', 2)],
           )

你甚至可以通過單個(gè)索引的笛卡爾積來構(gòu)造它:

pd.MultiIndex.from_product([['a', 'b'], [1, 2]])
MultiIndex([('a', 1),
            ('a', 2),
            ('b', 1),
            ('b', 2)],
           )

類似地,你可以通過直接傳遞 levels(每個(gè)層級可用索引值的列表)和 codes(引用這些標(biāo)簽的編碼列表)來使用其內(nèi)部編碼方式構(gòu)造一個(gè) MultiIndex

pd.MultiIndex(levels=[['a', 'b'], [1, 2]],
              codes=[[0, 0, 1, 1], [0, 1, 0, 1]])
MultiIndex([('a', 1),
            ('a', 2),
            ('b', 1),
            ('b', 2)],
           )

這些對象中的任何一個(gè)都可以作為 index 參數(shù)傳遞給 SeriesDataFrame 的構(gòu)造函數(shù),或者傳遞給已有 SeriesDataFramereindex 方法。

MultiIndex 層級命名

有時(shí)候,為 MultiIndex 的各層級命名會很方便。
這可以通過向前面討論過的任意一個(gè) MultiIndex 構(gòu)造器傳遞 names 參數(shù)來實(shí)現(xiàn),或者事后設(shè)置索引的 names 屬性也可以:

pop.index.names = ['state', 'year']
pop
state       year
California  2010    37253956
            2020    39538223
New York    2010    19378102
            2020    20201249
Texas       2010    25145561
            2020    29145505
dtype: int64

對于更復(fù)雜的數(shù)據(jù)集,這是一種有助于追蹤各索引值含義的實(shí)用方法。

列的 MultiIndex

DataFrame 中,行和列是完全對稱的,正如行可以有多級索引,列同樣也可以有多級索引。
請看下面這個(gè)例子,它模擬了一些(較為真實(shí)的)醫(yī)療數(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)建 DataFrame
health_data = pd.DataFrame(data, index=index, columns=columns)
health_data
subjectBobGuidoSue
typeHRTempHRTempHRTemp
yearvisit
2013139.036.136.037.325.037.4
243.036.133.038.337.037.7
2014160.036.69.036.937.037.5
243.037.324.037.641.034.8

這本質(zhì)上是一個(gè)四維數(shù)據(jù),其中維度分別是受試者、測量類型、年份和訪問次數(shù)。
有了這樣的結(jié)構(gòu),我們可以按人的名字索引頂層列,從而獲得只包含該人信息的完整 DataFrame

health_data['Guido']
typeHRTemp
yearvisit
2013136.037.3
233.038.3
201419.036.9
224.037.6

多重索引的索引與切片

MultiIndex 進(jìn)行索引和切片的設(shè)計(jì)非常直觀,如果你將索引看作是增加的維度會更容易理解。
我們將首先介紹對多重索引的 Series 進(jìn)行索引的方法,然后再介紹對多重索引的 DataFrame 對象進(jìn)行索引的方法。

多重索引的 Series

來看我們之前見過的州人口多重索引 Series 示例:

pop
state       year
California  2010    37253956
            2020    39538223
New York    2010    19378102
            2020    20201249
Texas       2010    25145561
            2020    29145505
dtype: int64

我們可以通過使用多個(gè)索引項(xiàng)來訪問單個(gè)元素:

pop['California', 2010]
np.int64(37253956)

MultiIndex 還支持部分索引,即只索引索引中的某一層級。
結(jié)果是另一個(gè) Series,并保留低層級的索引:

pop['California']
year
2010    37253956
2020    39538223
dtype: int64

只要 MultiIndex 已排序,也可以進(jìn)行部分切片:

pop.loc['California':'New York']
state       year
California  2010    37253956
            2020    39538223
New York    2010    19378102
            2020    20201249
dtype: int64

對于已排序的索引,可以通過在第一個(gè)索引位置傳遞一個(gè)空切片,實(shí)現(xiàn)對低層級的部分索引:

pop[:, 2010]
state
California    37253956
New York      19378102
Texas         25145561
dtype: int64

其他類型的索引和選擇(詳見數(shù)據(jù)索引與選擇)同樣適用;例如,可以使用布爾掩碼進(jìn)行選擇:

pop[pop > 22000000]
state       year
California  2010    37253956
            2020    39538223
Texas       2010    25145561
            2020    29145505
dtype: int64

花式索引(fancy indexing)同樣適用:

pop[['California', 'Texas']]
state       year
California  2010    37253956
            2020    39538223
Texas       2010    25145561
            2020    29145505
dtype: int64

多重索引的 DataFrame

多重索引的 DataFrame 具有類似的行為。
來看我們之前的醫(yī)療數(shù)據(jù)玩具 DataFrame 示例:

health_data
subjectBobGuidoSue
typeHRTempHRTempHRTemp
yearvisit
2013139.036.136.037.325.037.4
243.036.133.038.337.037.7
2014160.036.69.036.937.037.5
243.037.324.037.641.034.8

請記住,在 DataFrame 中列是主要的索引軸,對于多重索引的 Series,所用的語法同樣適用于列。
例如,我們可以通過一個(gè)簡單的操作獲取 Guido 的心率數(shù)據(jù):

health_data['Guido', 'HR']
year  visit
2013  1        36.0
      2        33.0
2014  1         9.0
      2        24.0
Name: (Guido, HR), dtype: float64

同樣地,和單層索引的情況一樣,我們可以使用在數(shù)據(jù)索引與選擇中介紹的 loc、ilocix 索引器。例如:

health_data.iloc[:2, :2]
subjectBob
typeHRTemp
yearvisit
2013139.036.1
243.036.1

這些索引器為底層的二維數(shù)據(jù)提供了類似數(shù)組的視圖,但在 lociloc 中,每個(gè)單獨(dú)的索引都可以傳遞一個(gè)包含多個(gè)索引的元組。例如:

health_data.loc[:, ('Bob', 'HR')]
year  visit
2013  1        39.0
      2        43.0
2014  1        60.0
      2        43.0
Name: (Bob, HR), dtype: float64

在這些索引元組中使用切片并不是特別方便;嘗試在元組中創(chuàng)建切片會導(dǎo)致語法錯(cuò)誤:

health_data.loc[(:, 1), (:, 'HR')]
  Cell In[32], line 1
    health_data.loc[(:, 1), (:, 'HR')]
                     ^
SyntaxError: invalid syntax

你可以通過顯式構(gòu)建所需的切片(使用 Python 內(nèi)置的 slice 函數(shù))來實(shí)現(xiàn)這一點(diǎn),但在這種情況下,更好的方法是使用 Pandas 專門為此場景提供的 IndexSlice 對象。
例如:

idx = pd.IndexSlice
health_data.loc[idx[:, 1], idx[:, 'HR']]
subjectBobGuidoSue
typeHRHRHR
yearvisit
2013139.036.025.0
2014160.09.037.0

如你所見,有許多方法可以與多重索引的 SeriesDataFrame 數(shù)據(jù)進(jìn)行交互。正如本書中的許多工具一樣,最好的熟悉方式就是親自嘗試!

重排多重索引

處理多重索引數(shù)據(jù)的關(guān)鍵之一是學(xué)會如何有效地轉(zhuǎn)換數(shù)據(jù)。
有許多操作可以在不丟失任何信息的前提下,重新排列數(shù)據(jù)集,以便進(jìn)行各種計(jì)算。
我們在 stackunstack 方法中已經(jīng)簡單見過這種操作,但實(shí)際上還有更多方法可以精細(xì)地控制分層索引與列之間的數(shù)據(jù)重排,下面我們將進(jìn)行詳細(xì)探討。

已排序與未排序的索引

前面我曾簡要提到一個(gè)注意事項(xiàng),這里需要特別強(qiáng)調(diào):
許多 MultiIndex 的切片操作如果索引未排序會失敗。
讓我們仔細(xì)看看這個(gè)問題。

我們先創(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.252857
      2      0.342139
c     1      0.732484
      2      0.740275
b     1      0.478320
      2      0.624116
dtype: float64

如果我們嘗試對這個(gè)索引進(jìn)行部分切片,將會導(dǎo)致錯(cuò)誤:

try:
    data['a':'b']
except KeyError as e:
    print("KeyError", e)
KeyError 'Key length (1) was greater than MultiIndex lexsort depth (0)'

雖然從錯(cuò)誤信息中并不十分清楚,但這實(shí)際上是由于 MultiIndex 沒有排序造成的。
出于多種原因,部分切片和其他類似操作要求 MultiIndex 的各層級必須是有序(即字典序)的。
Pandas 提供了許多便捷方法來進(jìn)行這種排序,比如 DataFramesort_indexsortlevel 方法。
這里我們將使用最簡單的 sort_index 方法:

data = data.sort_index()
data
char  int
a     1      0.252857
      2      0.342139
b     1      0.478320
      2      0.624116
c     1      0.732484
      2      0.740275
dtype: float64

通過這種方式對索引進(jìn)行排序后,部分切片將如預(yù)期般工作:

data['a':'b']
char  int
a     1      0.252857
      2      0.342139
b     1      0.478320
      2      0.624116
dtype: float64

索引的堆疊與反堆疊

如前所述,我們可以將數(shù)據(jù)集從堆疊的多重索引轉(zhuǎn)換為簡單的二維表示,并可選指定要使用的層級:

pop.unstack(level=0)
stateCaliforniaNew YorkTexas
year
2010372539561937810225145561
2020395382232020124929145505
pop.unstack(level=1)
year20102020
state
California3725395639538223
New York1937810220201249
Texas2514556129145505

unstack 的反操作是 stack,在這里可以用來恢復(fù)原始的 series:

pop.unstack().stack()
state       year
California  2010    37253956
            2020    39538223
New York    2010    19378102
            2020    20201249
Texas       2010    25145561
            2020    29145505
dtype: int64

索引的設(shè)置與重置

重排分層數(shù)據(jù)的另一種方式是將索引標(biāo)簽轉(zhuǎn)換為列,這可以通過 reset_index 方法實(shí)現(xiàn)。
對人口字典調(diào)用該方法會得到一個(gè)包含 stateyear 列的 DataFrame,這些信息原本存儲在索引中。
為了更清晰,我們還可以為數(shù)據(jù)列指定名稱,使其在列表示中更易理解:

pop_flat = pop.reset_index(name='population')
pop_flat
stateyearpopulation
0California201037253956
1California202039538223
2New York201019378102
3New York202020201249
4Texas201025145561
5Texas202029145505

一種常見的模式是根據(jù)列的值構(gòu)建 MultiIndex(多重索引)。
這可以通過 DataFrameset_index 方法實(shí)現(xiàn),該方法會返回一個(gè)具有多級索引的 DataFrame

pop_flat.set_index(['state', 'year'])
population
stateyear
California201037253956
202039538223
New York201019378102
202020201249
Texas201025145561
202029145505

在實(shí)際操作中,這種類型的重新索引是探索真實(shí)世界數(shù)據(jù)集時(shí)最有用的模式之一。

總結(jié)

本筆記系統(tǒng)介紹了 Pandas 的分層索引(MultiIndex)及其在 Series 和 DataFrame 中的應(yīng)用。內(nèi)容涵蓋了分層索引的創(chuàng)建方法(如 from_tuples、from_arrays、from_product 等)、索引和切片操作、索引排序、堆疊與反堆疊(stack/unstack)、索引與列之間的轉(zhuǎn)換(reset_index/set_index),以及多重索引在實(shí)際數(shù)據(jù)分析中的優(yōu)勢。通過豐富的代碼示例,展示了如何靈活、高效地處理高維數(shù)據(jù),并強(qiáng)調(diào)了分層索引在數(shù)據(jù)探索和處理中的重要作用。

到此這篇關(guān)于Pandas 分層索引的具體實(shí)踐的文章就介紹到這了,更多相關(guān)Pandas 分層索引內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

洪泽县| 陆丰市| 太湖县| 株洲县| 紫云| 荥阳市| 舟曲县| 苍南县| 尼玛县| 丹东市| 清水县| 游戏| 广南县| 涟源市| 雷山县| 高青县| 方正县| 丽江市| 大足县| 浙江省| 扶风县| 青神县| 永和县| 辉县市| 怀化市| 汽车| 依安县| 霞浦县| 西平县| 林西县| 萍乡市| 乐至县| 元阳县| 龙游县| 林芝县| 金湖县| 湖南省| 肃宁县| 晋江市| 犍为县| 成都市|