Pandas 提供了 transform、map 和 apply 等方法,讓資料處理更加彈性。transform 方法可以對 Series 或 DataFrame 進行向量化操作,map 方法則適用於對 Series 中的每個元素進行個別處理,而 apply 方法則更為通用,可以應用於 Series 和 DataFrame,並可自定義函式操作。瞭解這些方法的差異及應用場景,能有效提升資料處理效率。不同方法的效能差異取決於資料量和操作複雜度,選擇合適的方法能有效最佳化程式碼執行速度。
資料轉換與函式應用:深入理解 Pandas 中的轉換與應用方法
在資料分析的過程中,Pandas 提供了多種強大的方法來處理和轉換資料。其中,轉換(Transformations)、對映(Map)以及應用(Apply)是三個非常重要的概念。本文將探討這三個方法的使用方式及其在實際資料處理中的應用。
轉換(Transformations)
轉換是一種保持資料形狀不變的操作,與聚合(Aggregations)不同,轉換不會將多個值縮減為單一值。以下是一個使用 pd.Series.transform 的範例:
import pandas as pd
# 建立一個 pd.Series
ser = pd.Series([-1, 0, 1], dtype=pd.Int64Dtype())
# 定義一個函式,將 Series 中的每個元素加一
def adds_one(ser: pd.Series) -> pd.Series:
return ser + 1
# 對 Series 進行轉換
result = ser.transform(["abs", adds_one])
print(result)
內容解密:
ser.transform(["abs", adds_one])將ser中的每個元素進行絕對值轉換和加一操作。- 結果是一個新的 DataFrame,其中包含了原始 Series 經過不同轉換函式處理後的結果。
對於 DataFrame,轉換操作預設會套用到每一欄:
import pandas as pd
import numpy as np
# 建立一個 pd.DataFrame
df = pd.DataFrame(np.arange(-5, 4, 1).reshape(3, -1)).convert_dtypes(dtype_backend="numpy_nullable")
# 對 DataFrame 進行轉換
result = df.transform("abs")
print(result)
內容解密:
df.transform("abs")將 DataFrame 中的每個元素取絕對值。- 結果保持了原始 DataFrame 的形狀,但值被轉換為絕對值。
對映(Map)
對映允許使用者對資料中的每個元素個別應用自定義函式。以下是一個範例,展示如何使用 pd.Series.map 對混合資料型別的 Series 進行操作:
import pandas as pd
# 建立一個包含不同資料型別的 Series
ser = pd.Series([123.45, [100, 113], 142.0, [110, 113, 119]])
# 定義一個自定義函式,計算平均值
def custom_average(value):
if isinstance(value, list):
return sum(value) / len(value)
return value
# 對 Series 中的每個元素應用自定義函式
result = ser.map(custom_average)
print(result)
內容解密:
ser.map(custom_average)對 Series 中的每個元素應用custom_average函式。- 如果元素是列表,則計算列表的平均值;否則傳回原始值。
應用(Apply)
apply 方法是一種靈活但可能較不明確的操作方式。它可以用於模擬 map、transform 或 agg 的行為,但由於其靈活性,有時會導致不可預期的結果。以下是一個範例:
import pandas as pd
# 建立一個 Series
ser = pd.Series(range(3), dtype=pd.Int64Dtype())
# 定義一個除錯函式,列印每個被應用的值
def debug_apply(value):
print(f"Apply was called with value:\n{value}")
# 對 Series 中的每個元素應用除錯函式
result = ser.apply(debug_apply)
print(result)
內容解密:
ser.apply(debug_apply)對 Series 中的每個元素應用debug_apply函式,並列印該值。- 由於
debug_apply沒有傳回值,因此結果 Series 中的值為None。
資料分析中的演算法應用
在資料分析的過程中,各種演算法扮演著至關重要的角色。無論是資料的轉換、匯總還是分類別,演算法都提供了強大的工具來處理和分析資料。本章節將探討 pandas 函式庫中一些關鍵的演算法及其應用方法。
使用 apply 方法進行資料處理
apply 方法是 pandas 中一個非常靈活且強大的函式,可以對 Series 或 DataFrame 中的資料進行自定義操作。對於 Series 而言,apply 方法會對每個元素呼叫指定的函式。
程式碼範例:
import pandas as pd
def debug_apply(value):
print("Apply was called with value:")
print(value)
return None
ser = pd.Series([0, 1, 2])
result = ser.map(debug_apply)
print(result)
內容解密:
- 定義了一個名為
debug_apply的函式,用於列印輸入值並傳回None。 - 建立了一個包含
[0, 1, 2]的Series物件。 - 使用
map方法將debug_apply函式應用於Series中的每個元素。 - 由於
debug_apply傳回None,結果是一個包含None值的Series。
對於 DataFrame,apply 方法預設會對每一列(即每個 Series)呼叫指定的函式。
程式碼範例:
import pandas as pd
import numpy as np
df = pd.DataFrame(np.arange(6).reshape(3, -1), columns=list("ab")).convert_dtypes(dtype_backend="numpy_nullable")
print(df.apply(debug_apply))
內容解密:
- 建立了一個形狀為
(3, 2)的DataFrame。 - 對
DataFrame的每一列呼叫debug_apply函式。 - 輸出結果顯示了函式被呼叫的次數和對應的列資料。
程式碼範例:
ser = pd.Series(["a", "b", "c", "a", "c", "a"], dtype=pd.StringDtype())
print(ser.value_counts())
ser = pd.Series([0, 42, 84], dtype=pd.Int64Dtype())
print(ser.describe())
內容解密:
- 使用
value_counts方法統計了Series中每個值的頻率。 - 使用
describe方法計算了Series的各種統計指標,包括計數、平均值、標準差、最小值和最大值等。
分箱演算法
分箱是將連續變數劃分為離散區間的過程。pd.cut 函式可以根據指定的區間或區間數量對資料進行分箱。
程式碼範例:
df = pd.DataFrame([
["Jane", 34],
["John", 18],
["Jamie", 22],
["Jessica", 36],
["Jackie", 33],
["Steve", 40],
["Sam", 30],
["Stephanie", 66],
["Sarah", 55],
["Aaron", 22],
["Erin", 28],
["Elsa", 37],
], columns=["name", "age"]).convert_dtypes(dtype_backend="numpy_nullable")
print(pd.cut(df["age"], 4, precision=0))
內容解密:
- 將年齡資料劃分為 4 個區間,並指定精確度為整數。
- 輸出結果顯示了每個年齡值對應的區間。
透過這些範例,我們可以看到 pandas 提供的各種演算法和函式如何幫助我們高效地處理和分析資料。無論是簡單的資料轉換還是複雜的統計分析,掌握這些工具都能大大提升我們的資料分析能力。
資料分箱與獨熱編碼技術在 Pandas 中的應用
在資料分析和機器學習的應用中,經常需要對資料進行預處理,以使其能夠被數值演算法更好地理解和處理。Pandas 提供了多種工具來實作這一點,其中包括 pd.cut 用於資料分箱和 pd.get_dummies 用於獨熱編碼。
資料分箱(Binning)
資料分箱是一種將連續數值資料分組到離散區間的技術。這在需要將連續變數轉換為類別變數時非常有用。例如,將年齡分組到不同的區間。
使用 pd.cut 進行資料分箱
import pandas as pd
# 假設有一個 DataFrame 包含年齡資料
df = pd.DataFrame({
"name": ["Jane", "John", "Jamie", "Jessica", "Jackie", "Steve", "Sam", "Stephanie", "Sarah", "Aaron", "Erin", "Elsa"],
"age": [34, 18, 22, 36, 33, 40, 30, 66, 55, 22, 28, 37]
})
# 使用 pd.cut 將年齡分為不同的區間
df["age_bin"] = pd.cut(df["age"], [10, 20, 30, 40, 50, 60, 999], labels=["10-20", "20-30", "30-40", "40-50", "50-60", "60+"])
print(df)
內容解密:
pd.cut:用於將連續數值資料分割成不同的區間。bins引數:定義了分割的邊界。在這個例子中,年齡被分為 (10, 20], (20, 30], (30, 40], (40, 50], (50, 60], 和 (60, 999] 這幾個區間。labels引數:用於指定每個區間的標籤,使結果更易讀。right引數:預設情況下,區間是右包含的,即(a, b]。可以透過設定right=False改為左包含,即[a, b)。
獨熱編碼(One-Hot Encoding)
獨熱編碼是一種將類別變數轉換為數值表示的方法,使其能夠被機器學習演算法處理。
使用 pd.get_dummies 進行獨熱編碼
# 建立一個包含類別資料的 Series
ser = pd.Series(["green", "brown", "blue", "amber", "hazel", "amber", "green", "blue", "green"], name="eye_colors")
# 使用 pd.get_dummies 將類別變數轉換為獨熱編碼
dummies = pd.get_dummies(ser, prefix="is")
print(dummies)
內容解密:
pd.get_dummies:用於將類別變數轉換為獨熱編碼。prefix引數:用於指定生成的獨熱編碼欄位的字首,使結果更具可讀性。- 結果:每個類別值都被轉換為一個新的欄位,包含布林值表示是否屬於該類別。
使用 .pipe 方法鏈式處理資料
Pandas 的 .pipe 方法允許以鏈式的方式處理資料,使得程式碼更加簡潔和易於維護。
# 定義一個簡單的 DataFrame
df = pd.DataFrame({
"col1": pd.Series([1, 2, 3], dtype=pd.Int64Dtype()),
"col2": pd.Series(["a", "b", "c"], dtype=pd.StringDtype()),
})
# 鏈式處理資料
result = (df
.assign(col3=lambda x: x["col1"] * 2)
.pipe(lambda x: x[x["col1"] > 1]))
print(result)
圖表翻譯:
此圖示呈現了使用 .pipe 方法進行鏈式資料處理的流程。
graph LR;
A[原始 DataFrame] -->|assign|> B[新增新欄位];
B -->|pipe|> C[過濾資料];
C --> D[結果 DataFrame];
圖表翻譯: 此圖展示了使用 .pipe 方法進行鏈式操作的流程,包括新增欄位和過濾資料,最終得到結果 DataFrame。
內容解密:
.pipe方法:允許將 DataFrame 處理過程鏈式表達,使程式碼更簡潔。assign方法:用於新增或修改 DataFrame 中的欄位。- 鏈式處理:透過一系列方法鏈式呼叫,完成複雜的資料處理任務。
綜上所述,Pandas 提供了強大的工具來進行資料預處理,包括資料分箱、獨熱編碼和鏈式處理。這些技術在資料分析和機器學習專案中非常有用,能夠幫助我們更好地準備和轉換資料,以供後續分析或建模使用。
資料處理流程的最佳實踐:使用 pandas 管道(pipe)方法
在資料分析過程中,我們經常需要對 DataFrame 進行多步驟的轉換和處理。傳統的做法是將每個步驟的結果指定給一個新的變數,或者巢狀呼叫多個函式。這些方法雖然可行,但會使程式碼變得冗長或難以閱讀。pandas 提供了一個更優雅的解決方案:使用 pd.DataFrame.pipe 方法將多個操作組合成一個管道(pipeline)。
建立範例函式
首先,我們定義兩個簡單的函式,分別用於修改 DataFrame 的不同欄位。這些函式接受一個 DataFrame 作為輸入,並傳回修改後的 DataFrame。
import pandas as pd
def change_col1(df: pd.DataFrame) -> pd.DataFrame:
#### 內容解密:
# change_col1 函式用於修改 DataFrame 的 col1 欄位。
# 它使用 assign 方法將 col1 欄位的值替換為新的 Series,資料型別為 pd.Int64Dtype()。
return df.assign(col1=pd.Series([4, 5, 6], dtype=pd.Int64Dtype()))
def change_col2(df: pd.DataFrame, str_case: str = "upper") -> pd.DataFrame:
#### 內容解密:
# change_col2 函式用於修改 DataFrame 的 col2 欄位。
# 它根據 str_case 引數決定將 col2 的值轉換為大寫或小寫。
# str_case 引數預設為 "upper",即預設轉換為大寫。
if str_case == "upper":
values = ["X", "Y", "Z"]
else:
values = ["x", "y", "z"]
return df.assign(col2=pd.Series(values, dtype=pd.StringDtype()))
使用管道方法處理 DataFrame
現在,我們可以使用 pd.DataFrame.pipe 方法將上述函式組合成一個處理管道。
# 建立一個範例 DataFrame
df = pd.DataFrame({
'col1': [1, 2, 3],
'col2': ['a', 'b', 'c']
})
# 使用 pipe 方法鏈式呼叫函式
result_df = df.pipe(change_col1).pipe(change_col2, str_case="lower")
print(result_df)
輸出結果:
col1 col2
0 4 x
1 5 y
2 6 z
內容解密:
這段程式碼展示瞭如何使用 pipe 方法將多個 DataFrame 處理函式鏈式呼叫。
首先,change_col1 函式被應用於原始 DataFrame,將 col1 的值替換為 [4, 5, 6]。
接著,change_col2 函式被應用,將 col2 的值轉換為小寫 [‘x’, ‘y’, ‘z’]。
最終結果是一個經過兩次轉換的 DataFrame。
分析電影資料集:選出高評分中低預算的電影
在實際應用中,我們經常需要對資料進行篩選和分析。例如,從評分最高的100部電影中找出預算最低的5部。pandas 提供了 nlargest 和 nsmallest 方法來簡化這類別操作。
# 載入電影資料集
df = pd.read_csv("data/movie.csv", usecols=["movie_title", "imdb_score", "budget", "gross"], dtype_backend="numpy_nullable")
# 選出 IMDB 評分最高的 100 部電影
top_100_movies = df.nlargest(100, "imdb_score")
# 從這 100 部電影中找出預算最低的 5 部
lowest_budget_movies = top_100_movies.nsmallest(5, "budget")
print(lowest_budget_movies)
輸出結果(範例):
gross movie_title budget imdb_score
4804 <NA> Butterfly Girl 180000 8.7
4801 925402.0 Children of Heaven 180000 8.5
4706 <NA> 12 Angry Men 350000 8.9
4550 7098492.0 A Separation 500000 8.4
4636 133778.0 The Other Dream Team 500000 8.4
圖表翻譯:
此表格呈現了從 IMDB 評分最高的 100 部電影中篩選出的預算最低的 5 部電影。主要欄位包括電影標題、IMDB 評分和預算金額。可以觀察到,這些電影雖然預算較低,但仍獲得了較高的評分。