Pandas 的 pd.Series 和 pd.DataFrame 物件的核心概念在於其索引系統。理解 pd.Index 如何運作對於資料操作至關重要。預設情況下,Pandas 使用 pd.RangeIndex,但實際應用中,自定義索引更具彈性。設定自定義索引能讓資料更具語義,方便後續的篩選、排序和分析。除了索引,瞭解 pd.Series 和 pd.DataFrame 的各種屬性,例如 dtype、name、shape 和 size 等,能幫助開發者更有效率地檢視和操作資料。掌握這些基礎知識能為更進階的 Pandas 操作奠定堅實的基礎。
使用 Pandas 的索引與屬性
在使用 Pandas 構建 pd.Series 和 pd.DataFrame 物件時,你可能會注意到左側的數值從 0 開始,並在每一行資料中逐一遞增。這些數值由 pd.Index 物件負責。當你處理 pd.DataFrame 時,除了左側的行索引(row index)之外,還有一個上方的列索引(column index):
此圖示展示了
pd.DataFrame 的行和列索引
除了特定指定之外,Pandas 會自動為你建立一個自動編號的 pd.Index(技術上是一個 pd.RangeIndex,這是 pd.Index 類別的子類別)。然而,在實務應用中,很少使用 pd.RangeIndex 作為列索引,因為直接使用類別似於「City」或「Date」的列名更具表達性。在行索引中,pd.RangeIndex 出現較為常見,但你可能仍希望在那裡顯示自定義標籤。
自定義索引
在構建 pd.Series 和 pd.DataFrame 的過程中,你可以選擇覆寫預設的行和列索引。以下是如何在構建過程中自訂索引:
import pandas as pd
自訂 pd.Series 的行索引
# 自訂行索引
custom_index = ["dog", "cat", "human"]
series_with_custom_index = pd.Series([4, 4, 2], index=custom_index)
print(series_with_custom_index)
dog 4
cat 4
human 2
dtype: int64
自訂 pd.DataFrame 的行和列索引
# 自訂行和列索引
data = {
"age": [24, 42],
"height_cm": [180, 166],
"favorite_color": ["red", "blue"]
}
index = ["Jack", "Jill"]
columns = ["age", "height_cm", "favorite_color"]
df_with_custom_indices = pd.DataFrame(data, index=index, columns=columns)
print(df_with_custom_indices)
age height_cm favorite_color
Jack 24 180 red
Jill 42 166 blue
建立名稱為「animal」的索引並命名序列
index = pd.Index(["dog", "cat", "human"], name="animal")
named_series = pd.Series([4, 4, 2], name="num_legs", index=index)
print(named_series)
animal
dog 4
cat 4
human 2
Name: num_legs, dtype: int64
分析序列屬性
建立一個具有自定義索引並命名的 pd.Series:
index = pd.Index(["dog", "cat", "human"], name="animal")
ser = pd.Series([4, 4, 2], name="num_legs", index=index)
print(ser)
animal
dog 4
cat 4
human 2
Name: num_legs, dtype: int64
屬性分析
- 資料型別:使用
ser.dtype - 名稱:使用
ser.name - 索引:使用
ser.index - 形狀:使用
ser.shape - 大小:使用
ser.size - 長度:使用內建函式
len(ser)
分析資料框架屬性
建立一個具有自定義索引並命名的資料框架:
index = pd.Index(["Jack", "Jill"], name="person")
df = pd.DataFrame([
[24, 180, "red"],
[42, 166, "blue"]
], columns=["age", "height_cm", "favorite_color"], index=index)
print(df)
age height_cm favorite_color
person
Jack 24 180 red
Jill 42 166 blue
屬性分析
- 每列的資料型別:使用
df.dtypes - 行索引:使用
df.index - 列索引:使用
df.columns - 形狀:使用
df.shape - 大小:使用
df.size - 長度:使用內建函式
len(df)
概述
透過以上方式,玄貓展示瞭如何在構建 Pandas 的序列和資料框架時自訂其索引並分析其屬性。這些技巧可以幫助你更好地理解和操作資料結構,從而更高效地進行資料處理與分析工作。
選擇與指定
在前一章中,我們學習瞭如何建立 pd.Series 和 pd.DataFrame,並且瞭解它們與 pd.Index 的關係。現在,我們將重點轉向選擇與指定這些關鍵過程。選擇,也稱為索引,被視為一種取得器,用於從 Pandas 物件中檢索值。相對地,指定則是一種設定器,用於更新值。
本章的範例將從如何從 pd.Series 和 pd.DataFrame 物件中檢索值開始,逐步增加複雜度。我們最終會介紹 pd.MultiIndex,這可以用於分層選擇資料,並以介紹指定運算元結束。Pandas API 在選擇和指定方面非常注重重用相同的方法,這最終使我們能夠在與資料互動時表達出自己的意圖。
在本章結束時,您將能夠高效地從 Pandas 物件中檢索資料並更新其值。我們將在本章中涵蓋以下範例:
- 基本的 Series 選擇
- 基本的 DataFrame 選擇
- 根據位置的 Series 選擇
- 根據位置的 DataFrame 選擇
- 根據標籤的 Series 選擇
- 根據標籤的 DataFrame 選擇
- 混合根據位置和標籤的選擇
- DataFrame.filter
- 按資料型別選擇
- 透過布林陣列進行選擇/篩選
- 使用 MultiIndex – 單層級選擇
- 使用 MultiIndex – 複數層級選擇
- 使用 MultiIndex – 資料框
此外,還有一些關於指定運算元的介紹:
- 使用
.loc和.iloc的專案指定 - 資料框列指定
基本的 Series 選擇
從 pd.Series 中進行選擇涉及根據其位置或標籤來存取元素。這與透過索引存取列表中的元素或透過鍵存取字典中的元素類別似。pd.Series 物件的多功能性允許直觀且簡單地檢索資料,使其成為資料操作的重要工具。
pd.Series 被視為 Python 中的一個容器,就像內建的列表、元組和字典物件一樣。因此,對於簡單的選擇操作,使用者首先會考慮使用 Python 的索引操作員,即使用 [] 語法。
操作步驟
為了介紹基礎的選擇概念,我們從一個非常簡單的 pd.Series 開始:
ser = pd.Series(list("abc") * 3)
ser
0 a
1 b
2 c
3 a
4 b
5 c
6 a
7 b
8 c
dtype: object
在 Python 中,我們已經發現了 [] 操作員可以用來從容器中選取元素;例如, some_dictionary[0] 會給您與鍵 0 息配的值。對於 pd.Series ,基本選取行為類別似:
ser[3]
'a'
透過表示式 ser[3] ,Pandas 嘗試在 pd.Series 的索引中查詢標籤 3 ,如果只有一個比對項則傳回與該標籤相關聯的值。
除了從 pd.Series 中選取相關聯的值之外,您也可能希望傳回一個 pd.Series ,因為這樣可以讓標籤 3 與資料元素 “a” 延續關聯。透過提供一個包含單個元素的列表引數來實作:
ser[[3]]
3 a
dtype: object
延伸使用列表引數:如果您的列表包含多個元素,則可以從 pd.Series 中選取多個值:
ser[[0, 2]]
0 a
2 c
dtype: object
假設您使用預設索引:您可以使用類別似於切片 Python 列表的切片引數。例如:要取得不包括位置為3元素之前(但不包括)的一個 pd.Series 的部分元素:
ser[:3]
0 a
1 b
2 c
dtype: object
負切片索引對 Pandas 沒有問題。以下程式碼將選取 pd.Series 的最後四個元素:
ser[-4:]
5 c
6 a
7 b
8 c
dtype: object
您甚至可以提供帶有起始和停止引數的切片。以下程式碼將取得 pd.Series 中所有元素,從位置2開始到(但不包括)位置6:
ser[2:6]
2 c
3 a
4 b
5 c
dtype: object
上述切片範例使用起始、停止和步長引數來取得每第三個元素,從位置1開始到遇到位置8時停止:
ser[1:8:3]
1 b
4 b
7 b
dtype: object
#### 若以人話來說:
當我們說我們要切割一塊餅乾成三塊時(從索引1開始),分別拿起每三塊中第一塊餅乾放入盒子裡面(記得要跳過中間兩塊),直到拿到第八塊餅乾時停止。
這樣每三塊餅乾就會有一塊被放入盒子裡面。
接著我們來看看如何對自定義 pd.Index 值進行選取:
讓我們建立一個帶有字串索引標籤的小型 pd.Series ,以供說明:
```python
ser = pd.Series(range(3), index=["Jack", "Jill", "Jayne"])
這樣顯示結果是:
Jack 0
Jill 1
Jayne 2
dtype: int64
若以人話來說:
當你想要拿起某特定人的餅乾時(假設叫Jill),就直接去拿那張餅乾卡上面寫Jill名字的人。 如果你想要再仔細看清楚Jill有沒有被拿錯人時, 就直接把那張寫Jill名字的人拿出來仔細檢查一下。 接著我們再來看看第二個例子:
ser["Jill"]
顯示結果是:
1
若以人話來說:
你去找了寫著Jill名字的人, 然後發現他手上有一張餅乾卡, 因為你只想知道他手上的那張餅乾, 所以你就直接把他手上的那張餅乾卡拿走, 然後其他人都不知道你這樣做。 接著我們再來看看第三個例子:
ser[["Jill"]]
顯示結果是:
Jill 1
dtype: int64
若以人話來說:
你去找了寫著Jill名字的人, 然後發現他手上有一張餅乾卡, 因為你想知道他有沒有偷吃那張餅乾, 所以你就把他手上的那張餅乾卡給拿走, 然後其他人都知道你這樣做。 所以其實兩者差別就在於, 是否要讓其他人知道你已經拿走了某人的餅乾卡。
若以程式碼比喻:
當你想要透過Python程式碼來操作某資料時, 它有一種叫做「序列」(Series)跟「資料框」(Dataframe)資料結構。 當我想知道序列中的第幾筆資料時, 用方法「Series[index]」就是可以直接把該筆資料給抽出來。 但若我在抽出該筆資料後, 想要其他人也知道我已經抽出該筆資料時, 就要用「Series[[index]]」這個方法。 總之就是差別在於我是否想讓其他人知道我在抽資料。
其他需要注意事項:
一個常見陷阱是假設使用整數引數進行 [] 操作與從 Python 列表中進行選擇時具有相同行為。這只有在使用預設 pd.Index(技術上稱為 pd.RangeIndex)且該預設 Index 自動編號從0開始時才成立。
當不使用 pd.RangeIndex時需特別注意其行為。 例如:讓我們從一個小型 pd.Series 開始: 它仍然在其 pd.Index 中使用整數但不是自增序列開始於0:
ser = pd.Series(list("abc"), index=[2, 42, 21])
顯示結果是:
2 a
42 b
21 c
dtype: object
這裡很重要的一點是整數引數根據標籤而不是位置進行選取;即以下程式碼會傳回與標籤為2相關聯的值而不是位置2:
ser[2]
'a'
雖然整數引數按標籤比對而不是按位置, 但是切片仍按位置工作。 以下範例不會在遇到數字2時停止而是傳回前兩個元素:
ser[:2]
2 a
42 b
dtype: object
使用者還應熟悉在處理非唯一 pd.Index 的情況下如何進行選取: 例如:讓我們建立一個小型 pd.Series ,其中行索引中的號碼1出現兩次:
ser = pd.Series(["apple", "banana", "orange"], index=[0,1,1])
0 apple
1 banana
1 orange
dtype: object
對於此種 pd.Series ,嘗試按號碼1進行選取不會傳回單一值而是傳回另一個 pd.Series:
ser[1]
1 banana
1 orange
dtype: object
然而需要注意的是, 當使用預設 RangeIndex(即自增序列起始於0)進行 [] 操作時,
可能會混淆標籤或位置進行表示。 而實際上不同 Index型別下操作方式不同, 因此建議使用 .loc 和 .iloc方法 。