Pandas是Python資料科學領域的核心函式庫,其提供的資料重塑和轉換功能在資料分析中扮演著至關重要的角色。pivot函式能將資料從長格式轉換為寬格式,方便資料視覺化和分析。pivot_table更進一步允許在重塑的同時進行聚合操作,處理重複值。explode則能有效處理半結構化資料,將列表元素展開成獨立列,簡化資料處理流程。這些函式的組合使用能大幅提升資料整理效率,為後續分析奠定基礎。
資料重塑與轉換:深入理解 pandas 資料操作
在資料分析和處理的過程中,經常需要對資料進行重塑和轉換,以滿足不同的分析和應用需求。pandas 函式庫提供了強大的資料操作功能,其中包括 pd.DataFrame.pivot、pd.pivot_table 和 pd.DataFrame.explode 等函式,可以幫助我們有效地重塑和轉換資料。
使用 pd.DataFrame.pivot 進行資料重塑
pd.DataFrame.pivot 函式可以將資料從長格式(long format)轉換為寬格式(wide format)。它根據指定的索引(index)和欄位(columns)進行資料重塑,並將剩餘的欄位轉換為新的欄位值。
import pandas as pd
# 建立範例資料
data = {
"state": ["Arizona", "Florida", "Texas", "Arizona", "Florida", "Texas"],
"fruit": ["apple", "apple", "apple", "banana", "banana", "banana"],
"number_grown": [9, 0, 12, 12, 190, 40]
}
df = pd.DataFrame(data)
# 使用 pivot 進行資料重塑
wide_df = df.pivot(index="state", columns="fruit", values="number_grown")
print(wide_df)
內容解密:
df.pivot(index="state", columns="fruit", values="number_grown"):將state欄位設為索引,fruit欄位設為新的欄位名稱,number_grown欄位的值填入對應的儲存格中。- 資料重塑後,
wide_df成為一個寬格式的 DataFrame,其中每個水果種類別成為一個欄位,各州的水果產量填入對應的儲存格。
如果原始資料中存在重複的值,使用 pd.DataFrame.pivot 會導致錯誤。為瞭解決這個問題,可以使用 pd.pivot_table。
使用 pd.pivot_table 進行資料聚合和重塑
pd.pivot_table 函式不僅可以重塑資料,還可以對資料進行聚合操作。它允許指定聚合函式,以處理重複的值。
import pandas as pd
# 建立範例資料
data = {
"state": ["Texas", "Texas", "Arizona", "Arizona", "Texas", "Texas", "Arizona"],
"fruit": ["apple", "apple", "apple", "apple", "orange", "orange", "orange"],
"year": [2023, 2024, 2023, 2024, 2023, 2024, 2023],
"number_grown": [10, 2, 3, 6, 5, 5, 7],
"number_eaten": [6, 8, 7, 3, 2, 2, 2]
}
df = pd.DataFrame(data)
# 使用 pivot_table 進行資料聚合和重塑
pivot_table = pd.pivot_table(df, index="state", columns="fruit", values=["number_grown", "number_eaten"], aggfunc="sum")
print(pivot_table)
內容解密:
pd.pivot_table(df, index="state", columns="fruit", values=["number_grown", "number_eaten"], aggfunc="sum"):將state欄位設為索引,fruit欄位設為新的欄位名稱,對number_grown和number_eaten欄位的值進行求和聚合。- 資料重塑和聚合後,
pivot_table成為一個寬格式的 DataFrame,其中每個水果種類別成為一個欄位,各州的水果產量和食用量填入對應的儲存格,並進行求和聚合。
使用 pd.DataFrame.explode 將列表元素展開為獨立列
在處理半結構化資料時,經常遇到某個欄位包含列表或元組等非純量值的情況。pd.DataFrame.explode 函式可以將這些非純量值展開為獨立的列。
import pandas as pd
# 建立範例資料
data = {
"employee_id": [1, 2, 3],
"first_name": ["John", "Jane", "Joe"],
"last_name": ["Smith", "Doe", "Schmoe"],
"direct_reports": [[2, 3], [], []]
}
df = pd.DataFrame(data)
# 使用 explode 將列表元素展開為獨立列
df_exploded = df.explode("direct_reports")
print(df_exploded)
內容解密:
df.explode("direct_reports"):將direct_reports欄位中的列表元素展開為獨立的列。- 資料展開後,
df_exploded成為一個新的 DataFrame,其中每個直接下屬成為一個獨立的列。
資料重塑與轉置
在資料分析過程中,經常需要對資料進行重塑(reshaping)以滿足不同的分析需求。Pandas 提供了多種方法來實作資料重塑,包括 pd.DataFrame.explode 和 pd.DataFrame.T。
使用 pd.DataFrame.explode 展開資料
當資料中存在列表或陣列型別的欄位時,可以使用 pd.DataFrame.explode 將這些值展開成多行。
import pandas as pd
# 建立範例資料
data = [
{"employee_id": 1, "first_name": "John", "last_name": "Smith", "direct_reports": [2, 3]},
{"employee_id": 2, "first_name": "Jane", "last_name": "Doe", "direct_reports": []},
{"employee_id": 3, "first_name": "Joe", "last_name": "Schmoe", "direct_reports": []}
]
df = pd.DataFrame(data)
# 將 direct_reports 欄位展開
df_exploded = df.explode("direct_reports").convert_dtypes(dtype_backend="numpy_nullable")
內容解密:
pd.DataFrame.explode("direct_reports"):將direct_reports欄位中的列表值展開成多行。.convert_dtypes(dtype_backend="numpy_nullable"):轉換資料型別以支援 nullable 整數。
合併展開後的資料
可以將展開後的資料與原始資料合併,以取得更多資訊。
# 合併展開後的資料與原始資料
exploded = df.explode("direct_reports").convert_dtypes(dtype_backend="numpy_nullable")
merged_df = pd.merge(exploded, df.drop(columns=["direct_reports"]), how="left", left_on=["direct_reports"], right_on=["employee_id"], suffixes=("", "_direct_report"))
內容解密:
pd.merge:根據direct_reports和employee_id欄位進行左合併。suffixes=("", "_direct_report"):為合併後的欄位新增字尾,以區分原始欄位和合併欄位。
使用 PyArrow 的 struct 資料型別
PyArrow 提供了 struct 資料型別,可以用於處理半結構化資料。
import pyarrow as pa
import pandas as pd
# 定義 struct 資料型別
dtype = pd.ArrowDtype(pa.struct([("int_col", pa.int64()), ("str_col", pa.string()), ("float_col", pa.float64())]))
ser = pd.Series([{"int_col": 42, "str_col": "Hello, ", "float_col": 3.14159}, {"int_col": 555, "str_col": "world!", "float_col": 3.14159}], dtype=dtype)
# 使用 struct.explode 展開資料
ser_exploded = ser.struct.explode()
內容解密:
pd.ArrowDtype(pa.struct(...)):定義 PyArrow 的 struct 資料型別。.struct.explode():將 struct 中的欄位展開成多個欄位。
使用 pd.DataFrame.T 進行轉置
轉置是將 DataFrame 的行和列互換的操作。
# 建立範例資料
df = pd.DataFrame([[1, 2, 3], [4, 5, 6]], columns=list("xyz"), index=list("ab"))
# 進行轉置
df_transposed = df.T
內容解密:
df.T:將 DataFrame 的行和列互換。
為何需要轉置?
在某些情況下,轉置可以提高運算效率,特別是在避免使用 axis=1 引數時。
# 建立寬 DataFrame
import numpy as np
np.random.seed(42)
df = pd.DataFrame(np.random.randint(10, size=(2, 10_000)), index=list("ab"))
# 對比使用 axis=1 和轉置後的運算效率
def baseline_sum():
for _ in range(100):
df.sum(axis=1)
def transposed_sum():
transposed = df.T
for _ in range(100):
transposed.sum()
import timeit
print(timeit.timeit(baseline_sum, number=1))
print(timeit.timeit(transposed_sum, number=1))
內容解密:
df.sum(axis=1):對每行進行求和運算。df.T.sum():先轉置 DataFrame,然後對每列進行求和運算。
分組操作(Group By)
分組操作是資料分析中的基本任務之一,涉及將資料分成獨立的組,然後對每個組進行計算。
分割-應用-合併(Split-Apply-Combine)正規化
分組操作遵循分割-應用-合併正規化,其中應用步驟可以是還原(reduction)或轉換(transformation)。
圖表翻譯:
此圖表展示了分割-應用-合併正規化在還原和轉換中的應用。左側表示將資料分成多個組,中間表示對每個組進行計算,右側表示合併結果。
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333
title 圖表翻譯:
rectangle "分割" as node1
rectangle "應用" as node2
rectangle "合併" as node3
node1 --> node2
node2 --> node3
@enduml圖表翻譯: 此圖表說明瞭分組操作的流程,首先將原始資料分成多個獨立的組,然後對每個組進行計算,最後將結果合併。
Group By 基礎操作與應用
在 pandas 中,pd.DataFrame.groupby 方法是一個強大的工具,能夠對資料進行分組、套用函式並將結果合併。本文將介紹 Group By 的基本操作與進階應用。
Group By 基礎
Group By 的基本概念是將資料依據特定欄位進行分組,並對每個群組套用特定的函式。以下是一個簡單的範例:
import pandas as pd
# 建立範例資料
df = pd.DataFrame([
["group_a", 0],
["group_a", 2],
["group_b", 1],
["group_b", 3],
["group_b", 5],
], columns=["group", "value"])
# 將資料轉換為 numpy_nullable 型別
df = df.convert_dtypes(dtype_backend="numpy_nullable")
# 顯示原始資料
print("原始資料:")
print(df)
# 對 group 欄位進行 Group By,並計算 value 欄位的總和
grouped_df = df.groupby("group").sum()
# 顯示 Group By 結果
print("\nGroup By 結果:")
print(grouped_df)
內容解密:
- 建立範例資料:我們建立了一個簡單的 DataFrame,包含
group和value兩個欄位。 groupby方法:使用df.groupby("group")對group欄位進行分組。sum方法:對每個群組的value欄位計算總和。- 結果:最終結果顯示每個群組的
value總和。
Group By 進階應用
除了基本的總和計算外,Group By 還支援多種聚合函式和轉換操作。
聚合函式
# 使用 agg 方法進行聚合
df.groupby("group").agg("sum")
# 使用 NamedAgg 控制輸出欄位名稱
df.groupby("group").agg(sum_of_value=pd.NamedAgg(column="value", aggfunc="sum"))
內容解密:
agg方法:可以傳入聚合函式名稱(如 “sum”)進行計算。NamedAgg:用於控制輸出欄位的名稱,使結果更易讀。
轉換操作
# 使用 transform 方法進行轉換
df.groupby("group").transform("sum")
# 計算每個值佔群組總和的比例
df[["value"]].div(df.groupby("group").transform("sum"))
內容解密:
transform方法:對每個群組進行轉換,保持原始索引。- 比例計算:將每個
value除以其所在群組的總和,得到比例。
常見 Group By 演算法
pandas 提供多種內建的聚合和轉換演算法,包括:
聚合演算法
sum、prod、mean、median、var、stdmin、max、idxmin、idxmaxfirst、last、any、all
轉換演算法
cumprod、cumsum、cummin、cummaxrank
分組資料分析:Group By 的應用與實踐
在資料分析中,Group By 是一種常見的操作,用於根據特定欄位將資料分組並進行聚合運算。Pandas 提供了強大的 Group By 功能,使得資料分析變得更加高效。
Group By 的基本用法
在 Pandas 中,Group By 的基本用法是透過 df.groupby() 方法實作的。例如,假設我們有一個 DataFrame df,包含 group 和 value 兩個欄位,我們可以按照 group 欄位進行分組並計算每組的最大值:
df.groupby("group").max()
或者使用 agg() 方法:
df.groupby("group").agg("max")
兩種方法會得到相同的結果。
多欄位的 Group By 與聚合運算
在實際應用中,DataFrame 通常包含多個欄位。假設我們有一個 DataFrame,包含銷售資料和退貨資料,我們希望按照產品(widget)進行分組並計算總銷售額和總退貨額。
首先,建立一個範例 DataFrame:
df = pd.DataFrame([
["North", "Widget A", "Jan", 10, 2],
["North", "Widget B", "Jan", 4, 0],
["South", "Widget A", "Jan", 8, 3],
["South", "Widget B", "Jan", 12, 8],
["North", "Widget A", "Feb", 3, 0],
["North", "Widget B", "Feb", 7, 0],
["South", "Widget A", "Feb", 11, 2],
["South", "Widget B", "Feb", 13, 4],
], columns=["region", "widget", "month", "sales", "returns"])
df = df.convert_dtypes(dtype_backend="numpy_nullable")
方法一:選擇特定欄位進行聚合
df.groupby("widget")[["sales", "returns"]].agg("sum")
方法二:使用 pd.NamedAgg 進行聚合並重新命名欄位
df.groupby("widget").agg(
sales_total=pd.NamedAgg(column="sales", aggfunc="sum"),
returns_total=pd.NamedAgg(column="returns", aggfunc="sum"),
)
多重分組與多重聚合函式
Pandas 的 Group By 功能也支援多重分組和多重聚合函式。例如,我們可以按照 widget 和 region 兩個欄位進行分組,並計算多個聚合指標:
df.groupby(["widget", "region"]).agg(
sales_total=pd.NamedAgg("sales", "sum"),
returns_total=pd.NamedAgg("returns", "sum"),
sales_min=pd.NamedAgg("sales", "min"),
returns_min=pd.NamedAgg("returns", "min"),
)
內容解密:
- 多重分組:透過傳入一個列表給
groupby()方法,可以實作多重分組。 - 多重聚合函式:使用
agg()方法並傳入多個pd.NamedAgg物件,可以對不同的欄位應用不同的聚合函式。 - 結果解析:結果中會顯示每個分組的多個聚合指標,有助於更全面地瞭解資料特徵。
自定義聚合函式
雖然 Pandas 提供了許多內建的聚合函式,但在某些情況下,我們仍需要自定義聚合函式。例如,計算每組的眾數(mode)。由於 Pandas 的 groupby() 不直接支援 mode 操作,我們需要自行實作。
df = pd.DataFrame([
["group_a", 42],
["group_a", 555],
["group_a", 42],
["group_a", 555],
["group_b", 0],
], columns=["group", "value"])
對於自定義函式,可以透過 apply() 方法實作。