在資料科學領域,使用 pandas 處理 DataFrame 是家常便飯。熟練掌握資料篩選和指定技巧能大幅提升程式碼效率和可讀性。本文將介紹如何混合使用 .loc
和 .iloc
進行標籤和位置篩選,並探討 filter
方法的應用。此外,我們還會深入研究如何利用 get_indexer
最佳化效能,並解析布林陣列、MultiIndex 和布林運算元在資料篩選中的應用場景。最後,文章將示範如何在 DataFrame 中進行欄位指定,包含單層索引和多層索引的情況,並介紹如何使用 assign
方法實作優雅的鏈式操作。
資料篩選與指定:混合使用標籤與位置篩選
在 pandas 的資料處理中,經常需要在 DataFrame 中進行資料篩選與指定。pandas 提供了 .loc
和 .iloc
兩種方法,分別用於標籤式和位置式篩選。本章節將探討如何混合使用這兩種方法,以及如何使用 DataFrame.filter
方法進行資料篩選。
混合使用標籤與位置篩選
當需要根據標籤篩選某一維度,而根據位置篩選另一維度時,使用者必須採取額外步驟。因為 .iloc
是用於位置式篩選,而 .loc
是用於標籤式篩選。
程式碼範例:
import pandas as pd
# 建立一個 DataFrame
df = pd.DataFrame([
[24, 180, "blue"],
[42, 166, "brown"],
[22, 160, "green"],
], columns=["age", "height_cm", "eye_color"])
# 使用 get_indexer 將標籤轉換為位置索引
col_idxer = df.columns.get_indexer(["age", "eye_color"])
print(col_idxer) # 輸出:array([0, 2])
# 使用 .iloc 進行位置式篩選
print(df.iloc[[0, 1], col_idxer])
#### 內容解密:
- `df.columns.get_indexer(["age", "eye_color"])` 用於取得 "age" 和 "eye_color" 欄位的位置索引。
- `df.iloc[[0, 1], col_idxer]` 使用取得的位置索引對 DataFrame 進行篩選,選取第 0 和第 1 列,以及 "age" 和 "eye_color" 欄位。
輸出結果:
age eye_color
0 24 blue
1 42 brown
使用 DataFrame.filter
方法
DataFrame.filter
是一個專門用於從 DataFrame 的列或欄中篩選資料的方法。
程式碼範例:
# 建立一個具有自定義索引的 DataFrame
df = pd.DataFrame([
[24, 180, "blue"],
[42, 166, "brown"],
[22, 160, "green"],
], columns=["age", "height_cm", "eye_color"], index=["Jack", "Jill", "Jayne"])
# 使用 filter 方法篩選欄位
print(df.filter(["age", "eye_color"]))
#### 內容解密:
- `df.filter(["age", "eye_color"])` 用於篩選出 "age" 和 "eye_color" 欄位。
- `df.filter(["Jack", "Jill"], axis=0)` 用於篩選出 "Jack" 和 "Jill" 列。
輸出結果:
age eye_color
Jack 24 blue
Jill 42 brown
Jayne 22 green
效能比較
使用 get_indexer
方法與分步篩選方法的效能比較:
import timeit
def get_indexer_approach():
col_idxer = df.columns.get_indexer(["age", "eye_color"])
return df.iloc[[0, 1], col_idxer]
def two_step_approach():
return df[["age", "eye_color"]].iloc[[0, 1]]
print(timeit.timeit(get_indexer_approach, number=10000))
print(timeit.timeit(two_step_approach, number=10000))
#### 內容解密:
- `get_indexer_approach` 使用 `get_indexer` 方法進行混合式篩選。
- `two_step_approach` 使用分步篩選方法。
- `timeit.timeit` 用於比較兩種方法的執行時間。
結果分析:
使用 get_indexer
方法通常比分步篩選方法更高效,因為它避免了建立中間 DataFrame。
graph LR; A[開始] --> B[建立 DataFrame]; B --> C[使用 get_indexer 方法]; C --> D[使用 .iloc 方法]; D --> E[輸出結果]; B --> F[使用 filter 方法]; F --> G[輸出結果];
圖表翻譯:
此圖表呈現了兩種不同的資料篩選流程。首先,建立一個 DataFrame,然後可以選擇使用 get_indexer
方法結合 .iloc
方法進行混合式篩選,或者直接使用 filter
方法進行資料篩選,最終輸出結果。兩種方法都能有效地達到資料篩選的目的,但在使用大型資料集時,get_indexer
方法具有更好的效能表現。
資料篩選與指定
使用標籤進行篩選
在 pandas 中,可以使用 like=
和 regex=
引數根據標籤進行篩選。
使用 like=
引數
df.filter(like="_")
這個範例會選取任何包含底線(_)的欄位標籤。
使用 regex=
引數
df.filter(regex=r"^Ja.*(?<!e)$", axis=0)
這個範例會選取任何以 “Ja” 開頭但不以 “e” 結尾的列標籤。
根據資料型別進行篩選
可以使用 select_dtypes
方法根據資料型別進行篩選。
範例程式碼
df = pd.DataFrame([
[0, 1.0, "2"],
[4, 8.0, "16"],
], columns=["int_col", "float_col", "string_col"])
# 選取整數型別的欄位
df.select_dtypes("int")
內容解密:
pd.DataFrame.select_dtypes("int")
用於選取整數型別的欄位。- 可以透過傳遞列表引數來選取多種型別的欄位,例如
df.select_dtypes(include=["int", "float"])
。 - 使用
exclude=
引數可以排除特定型別的欄位,例如df.select_dtypes(exclude=["int", "float"])
。
使用布林陣列進行篩選
可以使用布林陣列(也稱為遮罩)來選取資料的子集。
範例程式碼
mask = [True, False, True]
ser = pd.Series(range(3))
# 使用遮罩選取資料
ser[mask]
內容解密:
ser[mask]
會傳回遮罩中對應值為True
的列。pd.Series.loc
方法與pd.Series[]
在此例中的行為相同。- 當使用布林陣列作為
pd.DataFrame[]
的引數時,會沿著列進行匹配。
組合布林運算元進行篩選
可以使用布林運算元(如 OR、AND、INVERT)來組合遮罩。
範例程式碼
blue_eyes = df["eye_color"] == "blue"
green_eyes = df["eye_color"] == "green"
mask = blue_eyes | green_eyes
# 使用組合遮罩選取資料
df[mask]
內容解密:
blue_eyes | green_eyes
使用 OR 運算元組合兩個遮罩,選取眼睛顏色為藍色或綠色的記錄。- 可以使用 AND 運算元
&
來選取滿足多個條件的記錄。 - INVERT 運算元
~
可以用來反轉遮罩,選取不滿足特定條件的記錄。
使用 MultiIndex 進行篩選
pd.MultiIndex
支援階層式標籤,可以使用 pd.DataFrame.loc
方法進行篩選。
範例程式碼
index = pd.MultiIndex.from_tuples([
("John", "Smith"),
("Jane", "Doe"),
])
# 建立一個簡單的 Series
ser = pd.Series(range(2), index=index)
# 使用 loc 方法進行篩選
ser.loc[("John", "Smith")]
內容解密:
pd.MultiIndex.from_tuples
用於從元組列表建立pd.MultiIndex
。- 使用
pd.DataFrame.loc
方法可以避免使用pd.DataFrame[]
時可能出現的歧義。
使用 pd.MultiIndex
進行資料選擇與指定
在 pandas 中,pd.MultiIndex
提供了一種強大的方式來處理具有多層索引的資料。本文將探討如何使用 pd.MultiIndex
進行資料選擇與指定。
建立 pd.MultiIndex
首先,我們需要建立一個 pd.MultiIndex
物件。這可以透過 pd.MultiIndex.from_tuples()
方法實作:
index = pd.MultiIndex.from_tuples([
("John", "Smith"),
("John", "Doe"),
("Jane", "Doe"),
("Stephen", "Smith"),
], names=["first_name", "last_name"])
內容解密:
pd.MultiIndex.from_tuples()
:用於從元組列表建立pd.MultiIndex
。names
引數:用於指定各層索引的名稱。
使用 pd.Series.loc
進行選擇
建立好 pd.MultiIndex
後,我們可以將其用於 pd.Series
的索引:
ser = pd.Series(range(4), index=index)
ser
輸出結果:
first_name last_name
John Smith 0
Doe 1
Jane Doe 2
Stephen Smith 3
dtype: int64
內容解密:
ser.loc["John"]
:選擇第一層索引為 “John” 的所有資料。ser.loc[["John"]]
:同樣選擇第一層索引為 “John” 的資料,但保留pd.MultiIndex
的結構。
多層索引的選擇
我們可以透過傳遞元組給 loc
方法來選擇多層索引的資料:
ser.loc[("Jane", "Doe")]
輸出結果:2
內容解密:
ser.loc[("Jane", "Doe")]
:選擇第一層索引為 “Jane” 且第二層索引為 “Doe” 的資料。ser.loc[(["Jane"], "Doe")]
:同樣選擇上述資料,但保留pd.MultiIndex
的結構。
使用 slice(None)
進行選擇
有時,我們需要選擇某一層索引的所有資料,可以使用 slice(None)
:
ser.loc[(slice(None), "Doe")]
輸出結果:
first_name
John 1
Jane 2
dtype: int64
內容解密:
slice(None)
:代表選擇該層索引的所有資料。ser.loc[(slice(None), ["Doe"])]
:選擇第二層索引為 “Doe” 的所有資料,並保留pd.MultiIndex
的結構。
使用 pd.IndexSlice
簡化語法
為了簡化使用 slice(None)
的語法,pandas 提供了 pd.IndexSlice
:
ixsl = pd.IndexSlice
ser.loc[ixsl[:, ["Doe"]]]
輸出結果:
first_name last_name
John Doe 1
Jane Doe 2
dtype: int64
內容解密:
pd.IndexSlice
:提供了一種更自然的方式來進行切片操作。
在 pd.DataFrame
中使用 pd.MultiIndex
我們也可以在 pd.DataFrame
中使用 pd.MultiIndex
作為行索引和列索引:
row_index = pd.MultiIndex.from_tuples([
("John", "Smith"),
("John", "Doe"),
("Jane", "Doe"),
("Stephen", "Smith"),
], names=["first_name", "last_name"])
col_index = pd.MultiIndex.from_tuples([
("music", "favorite"),
("music", "last_seen_live"),
("art", "favorite"),
], names=["art_type", "category"])
df = pd.DataFrame([
["Swift", "Swift", "Matisse"],
["Mozart", "T. Swift", "Van Gogh"],
["Beatles", "Wonder", "Warhol"],
["Jackson", "Dylan", "Picasso"],
], index=row_index, columns=col_index)
內容解密:
- 建立了一個具有多層行索引和列索引的
pd.DataFrame
。
使用 .loc
和 .iloc
進行指定
pandas 主要最佳化了資料的讀取和探索,但我們仍然可以使用 .loc
和 .iloc
進行資料的修改:
ser = pd.Series(range(3), index=list("abc"))
ser.loc["b"] = 42
輸出結果:
a 0
b 42
c 2
dtype: int64
內容解密:
- 使用
.loc
將索引為 “b” 的值修改為 42。
總之,本文介紹瞭如何使用 pd.MultiIndex
在 pandas 中進行資料選擇和指定。無論是單層還是多層索引,pandas 都提供了靈活的方法來操作資料。透過瞭解這些方法,我們可以更有效地處理和分析具有複雜索引結構的資料。
資料選擇與指定
在 pandas 中,資料的選擇與指定是常見的操作。本章節將介紹如何使用 pd.Series
和 pd.DataFrame
進行資料的選擇與指定。
使用 pd.Series.loc
和 pd.Series.iloc
進行指定
當需要對 pd.Series
中的特定元素進行指定時,可以使用 loc
和 iloc
方法。loc
方法根據標籤進行指定,而 iloc
方法則根據位置進行指定。
ser = pd.Series([0, 1, 2], index=list("abc"))
ser.loc["b"] = 42
ser
內容解密:
ser.loc["b"] = 42
將ser
中標籤為 “b” 的元素指定為 42。- 使用
loc
方法可以根據標籤對特定的元素進行修改。
ser.iloc[2] = -42
ser
內容解密:
ser.iloc[2] = -42
將ser
中位置為 2 的元素(即第三個元素)指定為 -42。- 使用
iloc
方法可以根據位置對特定的元素進行修改。
資料框(DataFrame)的欄位指定
對 pd.DataFrame
指定新欄位是一項常見的操作。可以使用 pd.DataFrame[]
運算元來新增欄位。
df = pd.DataFrame({"col1": [1, 2, 3]})
df["new_column1"] = 42
df
內容解密:
df["new_column1"] = 42
新增了一個名為 “new_column1” 的欄位,並將所有元素指定為 42。- 這種操作會將標量值廣播到 DataFrame 的每一行。
df["new_column2"] = list("abc")
df["new_column3"] = pd.Series(["dog", "cat", "human"])
df
內容解密:
df["new_column2"] = list("abc")
新增了一個名為 “new_column2” 的欄位,並將其指定為列表 [“a”, “b”, “c”]。df["new_column3"] = pd.Series(["dog", "cat", "human"])
新增了一個名為 “new_column3” 的欄位,並將其指定為一個 Series。- 這兩種操作都需要確保指定的序列長度與 DataFrame 的行數相匹配。
對具有多層索引(MultiIndex)的 DataFrame 進行指定
當 DataFrame 具有多層索引時,可以透過傳遞 tuple 給 pd.DataFrame.loc
來進行指定。
row_index = pd.MultiIndex.from_tuples([
("John", "Smith"),
("John", "Doe"),
("Jane", "Doe"),
("Stephen", "Smith"),
], names=["first_name", "last_name"])
col_index = pd.MultiIndex.from_tuples([
("music", "favorite"),
("music", "last_seen_live"),
("art", "favorite"),
], names=["art_type", "category"])
df = pd.DataFrame([
["Swift", "Swift", "Matisse"],
["Mozart", "T. Swift", "Van Gogh"],
["Beatles", "Wonder", "Warhol"],
["Jackson", "Dylan", "Picasso"],
], index=row_index, columns=col_index)
df.loc[:, ("art", "museuems_seen")] = [1, 2, 4, 8]
df
內容解密:
df.loc[:, ("art", "museuems_seen")] = [1, 2, 4, 8]
在 “art” 索引下新增了一個名為 “museuems_seen” 的欄位,並將其指定為 [1, 2, 4, 8]。- 這種操作展示瞭如何對具有多層索引的 DataFrame 進行欄位新增和指定。
使用 pd.DataFrame.assign
方法進行鏈式操作
pd.DataFrame.assign
方法允許在鏈式操作中新增欄位,這對於保持程式碼的連貫性和可讀性非常有幫助。
df = pd.DataFrame([[0, 1], [2, 4]], columns=list("ab"))
(
df
.mul(2)
.add(42)
.assign(chained_c=lambda df: df["b"] - 3)
)
內容解密:
.mul(2)
將 DataFrame 中的每個元素乘以 2。.add(42)
將上一步的結果加上 42。.assign(chained_c=lambda df: df["b"] - 3)
新增了一個名為 “chained_c” 的欄位,其值為原 DataFrame 中 “b” 欄位的值減去 3。- 這種鏈式操作使得程式碼更加簡潔和易於理解。