Series和DataFrame提供了豐富的下标存取方法,除了直接使用[]運算符之外,還可以使用.loc[]、.iloc[]、.at[]、.iat[]和.ix[]等存取器存取其中的元素。
下面的表1總結了DataFrame對象的各種存取方法:
表1 DataFrame對象的各種存取方法
方法 | 說明 |
[col_label] | 以單個标簽作為下标,擷取與标簽對應的列,傳回Series對象 |
[col_labels] | 以标簽清單作為下标,擷取對應的多個列,傳回DataFrame對象 |
[row_slice] | 整數切片或标簽切片,得到指定範圍之内的行 |
[row_bool_array] | 選擇布爾數組中True對應的行 |
.get(col_label, default) | 與字典的get()方法的用法相同 |
.at[index_label, col_label] | 選擇行标簽和列标簽對應的值,傳回單個元素 |
.iat[index, col] | 選擇行編号和列編号對應的值,傳回單個元素 |
.loc[index, col] | 通過單個标簽值、标簽清單、标簽數組、布爾數組、标簽切片等選擇指定行與列上的資料 |
.iloc[index, col] | 通過單個整數值、整數清單、整數數組、布爾數組、整數切片選擇指定行與列上的資料 |
.ix[index, col] | 同時擁有.loc[]和.iloc[]的功能,既可以使用标簽下标也可以使用整數下标 |
.lookup(row_labels, col_labels) | 選擇行标簽清單與列标簽清單中每對标簽對應的元素值 |
.get_value(row_label, col_label) | 與.at[]的功能類似,不過速度更快 |
.query() | 通過表達式選擇滿足條件的行 |
.head() | 擷取頭部N行資料 |
.tail() | 擷取尾部N行資料 |
np.random.seed(42)
df = pd.DataFrame(np.random.randint(0, 10, (5, 3)),
index=["r1", "r2", "r3", "r4", "r5"],
columns=["c1", "c2", "c3"])
一、[]操作符
通過[]操作符對DataFrame對象進行存取時,支援以下5種下标對象:
·單個索引标簽:擷取标簽對應的列,傳回一個Series對象。
·多個索引标簽:擷取以清單、數組(注意不能是元組)表示的多個标簽對應的列,傳回一個DataFrame對象。
·整數切片:以整數下标擷取切片對應的行。
·标簽切片:當使用标簽作為切片時包含終值。
·布爾數組:擷取數組中True對應的行。
·布爾DataFrame:将DataFrame對象中False對應的元素設定為NaN。
下面顯示整數切片和标簽切片的結果,注意标簽切片包含終值"r4":
df.c1 > 4是一個布爾序列,是以df[df.c1 > 4]獲得該序列中True對應的行。df > 2是一個布爾DataFrame對象,df[df > 2]将其中False對應的元素置換為NaN:
二、.loc[]和.iloc[]存取器
.loc[]的下标對象是一個元組,其中的兩個元素分别與DataFrame的兩個軸相對應。若下标不是元組,則該下标對應第0軸,:對應第1軸。每個軸的下标對象都支援單個标簽、标簽清單、标簽切片以及布爾數組。
df.loc["r2"]獲得"r2"對應的行,它傳回一個Series對象。df.loc["r2", "c2"]獲得"r2"行"c2"列的元素,它傳回單個元素值。
df.loc[["r2", "r3"]]獲得"r2"和"r3"對應的行。df.loc[["r2","r3"],["c1","c2"]]則獲得"r2"和"r3"行、"c1"和"c2"列上的資料,所得到的資料都是新的DataFrame對象。
在下面的程式中,第0軸的下标分别為标簽切片和布爾數序列:
.iloc[]和loc[]類似,不過它使用整數下标:
此外.ix[]的存取器可以混用标簽和位置下标,例如:
如果DataFrame對象有整數索引,則應該使用.loc[]和.iloc[]以避免混淆。
三、擷取單個值
.at[]和.iat[]分别使用标簽和整數下标擷取單個值,此外get_value()與.at[]類似,不過其執行速度要快一些:
當.loc[]的下标對象是兩個标簽清單時,所獲得的是這兩個清單形成的網格上的元素,這與NumPy的數組下标操作不一樣。如果希望擷取兩個清單中每對标簽所對應的元素,可以使用lookup(),它傳回一個包含指定元素的數組:
df.lookup(["r2", "r4", "r3"], ["c1", "c2", "c1"])
array([4, 3, 2])
四、多級标簽的存取
.loc[]和.at[]的下标可以指定多級索引中每級索引上的标簽。這時多級索引軸對應的下标是一個下标元組,該元組中的每個元素與索引中的每級索引對應。若下标不是元組,則将其轉換為長度為1的元組,若元組的長度比索引的層數少,則在其後面補slice(None)。
soil_df = pd.read_csv("data/Soils-simple.csv", index_col=[0, 1], parse_dates=["Date"])
在下面的例子中,"10-30"為第0軸的标簽,根據前面的規則,将其轉換為("10-30", slice(None)),即選擇第0級中"10-30"對應的行:
如果需要選擇第1級中"Top"對應的行,則需要把slice(None)作為第0級的下标。由于Python中隻有直接在[]中才能使用以:分隔的切片文法,是以這裡使用np.s_對象建立第0軸對應的下标:(slice(None), "Top")。
五、query()方法
當需要根據一定的條件對行進行過濾時,通常可以先建立一個布爾數組,使用該數組擷取True對應的行,例如下面的程式獲得pH值大于5、Ca含量小于11%的行。由于Python中無法自定義not、and和or等關鍵字的行為,是以需要改用~、&、|等位運算符。然而這些運算符的優先級比比較運算符要高,是以需要用括号将比較運算括起來:
soil_df[(soil_df.pH > 5) & (soil_df.Ca < 11)]
使用query()可以簡化上述程式:
query()的參數是一個運算表達式字元串。其中可以使用not、and和or等關鍵字進行向量布爾運算,表達式中的變量名表示與其對應的列。如果希望在表達式中使用其他全局或局域變量的值,可以在變量名之前添加@,例如:
pH_low = 5
Ca_hi = 11
print soil_df.query("pH > @pH_low and Ca < @Ca_hi")