Python Pandas 索引與分組操作精解
在資料分析領域,Pandas 以其強大的資料處理能力而備受推崇。其中,索引和分組操作更是精華所在,能大幅提升資料處理的效率。本文將結合個人經驗,深入淺出地解析 Pandas 的索引機制、GroupBy
操作,以及實用的切片和篩選技巧。
索引機制:資料存取的根本
不同於 SAS 資料集需要額外建立索引,Pandas DataFrame
在建立時便自動產生行列索引,預設的 RangeIndex
類別似 SAS 的 _N_
變數。更重要的是,Pandas 的索引機制賦予每一列獨特的標籤,如同資料函式庫的主鍵,方便快速定位和擷取資料。除了預設的整數索引,我們還能以特定欄位建立索引,甚至建立多層次的 MultiIndex
。
缺失值處理:fillna()
的妙用
真實資料中,缺失值無可避免。Pandas 提供 fillna()
方法填補缺失值,確保資料完整性。以下分享幾種 fillna()
的應用場景:
- 以零填補:
import pandas as pd
import numpy as np
data = {'溫度': ['低', '中', '高', '涼', '涼', None, None],
'速度': ['慢', '中', '快', None, '中', '慢', '慢'],
'測量值1': [np.nan, 4.2, 9.4, np.nan, 6.1, np.nan, np.nan],
'測量值2': [2.7, 5.1, 11.0, np.nan, 4.3, 2.9, 2.9],
'測量值3': [6.6, 7.9, np.nan, 9.1, 12.2, 3.3, 3.3],
'測量值4': [3.1, 9.1, 6.8, 8.9, 3.7, 1.7, 1.7]}
df = pd.DataFrame(data)
df_filled = df.fillna(0)
print(df_filled)
fillna(0)
將 DataFrame
中所有缺失值(數值型的 NaN
和字串型的 None
)替換為 0。在處理數值資料時,這是一種常見的缺失值填補策略。
- 針對特定欄位填補:
df_filled_subset = df[['測量值1', '測量值2', '測量值3', '測量值4']].fillna(0)
print(df_filled_subset)
此例僅針對 ‘測量值1’ 到 ‘測量值4’ 這些數值欄位填補缺失值,更精確地控制填補範圍。
- 使用字典填補:
fill_values = {'溫度': '低', '速度': '慢', '測量值1': 0, '測量值2': 0, '測量值3': 0, '測量值4': 0}
df_filled_dict = df.fillna(fill_values)
print(df_filled_dict)
使用字典,能為不同欄位指定不同的填補值,例如以 ‘低’ 填補 ‘溫度’,以 0 填補數值欄位,展現高度靈活性。
- 以平均值填補:
df_filled_mean = df[["測量值1", "測量值2", "測量值3"]].fillna(df.測量值4.mean())
print(df_filled_mean)
以 ‘測量值4’ 的平均值填補其他測量值欄位。當欄位間數值分佈相對均勻時,此法能有效維持資料的整體特性。
graph LR B[B] A[原始 DataFrame] --> B{fillna()} B --> C[以 0 填補] B --> D[以特定欄位填補] B --> E[以字典填補] B --> F[以平均值填補]
圖表説明:此流程圖展示 fillna()
的多種應用方式,讓您快速掌握不同填補策略。
切片與篩選:精準擷取資料
Pandas 提供多種切片和篩選方式,如同手術刀般精準擷取所需資料。
[]
運算元: 主要用於選取欄位,或搭配RangeIndex
選取列。
print(df[['溫度', '速度']]) # 選取 '溫度' 和 '速度' 欄位
[]
運算元搭配欄位名稱列表,即可選取特定欄位。
loc[]
索引器: 使用列標籤和欄位標籤進行選取。
df = df.set_index('溫度') # 將 '溫度' 設為索引
print(df.loc[['低', '高']]) # 選取索引標籤為 '低' 和 '高' 的列
loc[]
索引器以標籤為依據,精準選取特定列。
iloc[]
索引器: 使用整數位置進行選取。
print(df.iloc[:3]) # 選取前三列資料
iloc[]
索引器以整數位置為依據,類別似 Python 列表的切片操作。
- 布林索引: 根據條件篩選資料。
print(df[df['測量值1'] > 5]) # 選取 '測量值1' 大於 5 的列
布林索引提供更進階的篩選方式,根據條件選取符合的列,極具彈性。
graph LR A[DataFrame] --> B{選取方式?} B -- 標籤 --> C[loc] B -- 位置 --> D[iloc / ] B -- 條件 --> E[布林索引]
圖表説明:此圖表展示 Pandas 提供的多種資料選取方式,方便您根據需求選擇合適方法。
Pandas 的索引、fillna()
、切片和篩選功能,讓資料處理更精準高效。熟練運用這些技巧,您將能輕鬆駕馭 Pandas,提升資料分析效率。
在資料分析的過程中,我發現善用 Pandas 的索引和切片功能,能有效簡化程式碼,並提升執行效率。尤其是在處理大型資料集時,這些技巧更是不可或缺。
透過以上案例,我們可以看到 Pandas 的索引和切片功能的靈活性,可以根據不同的需求選擇不同的操作策略。
import pandas as pd
import numpy as np
# 設定顯示格式
pd.options.display.float_format = '{:,.2f}'.format
# 建立 MultiIndex (columns)
cols = pd.MultiIndex.from_tuples([
(x, y) for x in ['Test1', 'Test2', 'Test3'] for y in ['Pre', 'Post']
])
# 建立 MultiIndex (index)
rows = pd.MultiIndex.from_tuples([
(x, y) for x in ['A', 'B'] for y in ['One', 'Two']
])
np.random.seed(98765)
df = pd.DataFrame(np.random.randn(4, 6), index=rows, columns=cols)
print(df)
這段程式碼示範瞭如何建立更複雜的 MultiIndex
,並同時應用於 DataFrame 的行和列。這裡,我們分別為行和列建立了 MultiIndex
,然後使用這些 MultiIndex
建立 DataFrame。
graph LR A["建立 MultiIndex (columns)"] --> B["建立 MultiIndex (index)"] B --> C["建立 DataFrame"]
上圖展示了建立帶有 MultiIndex
的 DataFrame 的流程。
# 選擇特定資料
print(df['Test2']['Pre'])
透過多層索引,我們可以像使用字典一樣,逐層選取資料。df['Test2']['Pre']
先選取 ‘Test2’ 層級下的所有資料,再選取 ‘Pre’ 層級下的資料。
# 使用 xs() 選取特定層級的資料
print(df.xs('One', level=1)) # level=1 指的是第二層索引
xs()
方法可以根據特定層級的標籤值選取資料。df.xs('One', level=1)
選取第二層索引為 ‘One’ 的所有資料。
# 使用 stack() 和 unstack() 進行層級轉換
stacked = df.stack()
print(stacked)
unstacked = stacked.unstack()
print(unstacked)
stack()
方法可以將列索引的最後一層轉換為新的最內層列索引,而 unstack()
方法則可以將列索引的最內層轉換為新的最外層列索引。這些方法可以方便地調整資料的層級結構。
graph LR A[DataFrame] --> B[stack] B --> C[unstack] C --> D[DataFrame]
上圖展示了 stack()
和 unstack()
方法之間的轉換關係。
透過 MultiIndex
,我們可以更有效率地組織和處理高維資料,並利用 Pandas 提供的各種方法進行資料分析和轉換。
Pandas 的 MultiIndex
提供了處理高維資料的有效方法,讓資料的組織和分析更加便捷。透過理解 MultiIndex
的建立、選取和轉換方式,我們可以更好地應對複雜的資料分析任務。
import pandas as pd
import numpy as np
# 建立範例 DataFrame
years = [2015, 2016, 2017, 2018]
months = [1, 2, 3]
areas = ['City', 'Rural', 'Suburbs']
whens = ['Day', 'Night']
index = pd.MultiIndex.from_product([years, months], names=['Year', 'Month'])
columns = pd.MultiIndex.from_product([areas, whens], names=['Area', 'When'])
tickets = pd.DataFrame(np.random.randint(1, 50, size=(12, 6)), index=index, columns=columns)
# 選擇 'City' 在 'Day' 時間超過 25 的資料
city_day_over_25 = tickets[tickets[('City', 'Day')] > 25]
print(city_day_over_25)
# 選擇所有 'Day' 時間超過 25 的資料
day_over_25 = tickets[tickets.loc[:, idx[:, 'Day']].gt(25).any(axis=1)]
print(day_over_25)
第一個例子 tickets[tickets[('City', 'Day')] > 25]
選擇 ‘City’ 與 ‘Day’ 的值大於 25 的所有資料列。第二個例子 tickets[tickets.loc[:, idx[:, 'Day']].gt(25).any(axis=1)]
則更為複雜,它首先選取所有 'Day'
時間的資料,然後使用 .gt(25)
判斷是否大於 25,最後使用 .any(axis=1)
判斷每一列是否存在至少一個 True 值,從而選取符合條件的列。
使用 xs() 進行交叉切片
xs()
方法允許您在特定層級上進行切片,並傳回一個新的 DataFrame 或 Series。
# 選擇 2015 年所有月份的資料
tickets_2015 = tickets.xs(2015, level='Year')
print(tickets_2015)
# 選擇所有年份 3 月的資料
tickets_month_3 = tickets.xs(3, level='Month')
print(tickets_month_3)
tickets.xs(2015, level='Year')
選取 Year
層級為 2015 的所有資料,而 tickets.xs(3, level='Month')
選取 Month
層級為 3 的所有資料。xs()
方法提供了一種便捷的方式來提取特定層級的資料。
使用 groupby() 進行分組
groupby()
方法可以根據多層索引的層級對資料進行分組,並執行聚合操作。
# 根據 'Year' 和 'Area' 分組,並計算平均值
grouped = tickets.groupby(level=['Year', 'Area']).mean()
print(grouped)
這段程式碼根據 ‘Year’ 和 ‘Area’ 兩個層級對資料進行分組,並計算每個組的平均值。groupby()
方法結合多層索引可以輕鬆地進行複雜的資料聚合和分析。
graph LR B[B] A[原始 DataFrame] --> B{groupby} B --> C[分組後的 DataFrame]
總結:本文介紹了多層索引的進階操作技巧,包括使用 IndexSlice
、條件切片、xs()
交叉切片以及 groupby()
分組。這些技巧可以幫助您更有效地處理和分析複雜的資料結構。熟練掌握這些技巧將大幅提升您的資料分析效率。
import pandas as pd
# 建立範例 DataFrame
data = {'District': ['I', 'I', 'I', 'I', 'II', 'II', 'II', 'II', 'III', 'III', 'III', 'III', 'III'],
'Sector': ['North', 'South', 'East', 'West', 'North', 'South', 'East', 'West', 'North', 'South', 'East', 'West', 'West'],
'Name': ['Patton', 'Joyner', 'Williams', 'Jurat', 'Aden', 'Tanner', 'Jenkins', 'Milner', 'Chang', 'Gupta', 'Haskins', 'LeMay', 'LeMay'],
'Before': [17, 13, 111, 51, 71, 113, 99, 15, 69, 11, 45, 35, 35],
'After': [27, 22, 121, 55, 70, 122, 99, 65, 101, 22, 41, 69, 69],
'Age': [22, 19, 29, 22, 17, 32, 24, 22, 21, 21, 19, 20, 20]}
df = pd.DataFrame(data)
# 使用 pd.cut() 進行分組
bins = [0, 20, 30, 40, 50, 60]
group_names = ['0-20', '21-30', '31-40', '41-50', '51-60']
categories = pd.cut(df['Age'], bins, labels=group_names)
# 將分組結果增加到 DataFrame
df['Age Group'] = categories
# 根據年齡區間進行分組
grouped = df.groupby('Age Group')
# 顯示分組結果
for name, group in grouped:
print(f"Age Group: {name}")
print(group)
print("\n")
# 計算每個年齡區間的統計資訊
print(grouped.agg({'Before': 'mean', 'After': 'mean'}))
這段程式碼首先使用 pd.cut()
方法將 Age
欄位的值分割成不同的區間,並使用 labels
引數指定每個區間的名稱。然後,將分組結果增加到 DataFrame 的 Age Group
欄位。接著,使用 groupby()
方法根據 Age Group
欄位進行分組,並使用迴圈迭代每個組,顯示組名和組內資料。最後,使用 agg()
方法計算每個年齡區間的 ‘Before’ 和 ‘After’ 欄位的平均值。
graph LR A[DataFrame] --> B[pd.cut] B --> C[Categorical Data] C --> D[groupby] D --> E[Grouped DataFrame] E --> F[agg] F --> G[Statistics]
這個流程圖展示了使用 pd.cut()
和 groupby()
進行分組計算的流程。首先,pd.cut()
將數值資料轉換為分類別資料,然後 groupby()
根據分類別資料進行分組,最後使用 agg()
計算每個組的統計資訊。
透過以上方法,我們可以有效地根據連續數值欄位對資料進行分組,並進行更精細的分析。
Pandas 的 groupby()
方法是資料分析中不可或缺的工具,它可以幫助我們輕鬆地根據不同欄位對資料進行分組,並對每個組進行統計分析。結合 pd.cut()
方法,我們可以更靈活地處理連續數值欄位的分組,從而提取更有價值的資訊。記住善用視覺化圖表,例如 Mermaid 流程圖,可以更清晰地理解資料處理流程,並提升程式碼的可讀性。
連續數值欄位的Pandas分組技巧解析
在資料分析中,我們經常需要根據特定欄位對資料進行分組,然後對每個組進行統計分析。Pandas 的 groupby()
方法提供了一個強大與靈活的工具來實作這個目標。本文將重點探討如何使用 groupby()
處理連續數值欄位,並提供一個清晰的範例,展示如何使用 pd.cut()
方法將連續值分割到不同的區間,然後進行分組和統計分析。
import pandas as pd
# 範例資料
data = {'Age': [22, 38, 26, 35, 45, 60, 28, 32, 55, 70]}
df = pd.DataFrame(data)
# 定義統計函式
def stats(x):
return {'count': x.count(), 'min': x.min(), 'max': x.max(), 'mean': x.mean()}
# 定義區間和標籤
bins = [0, 25, 50, 75, 200]
gp_labels = ['0 to 25', '26 to 50', '51 to 75', 'Over 75']
# 使用 pd.cut() 方法
df['Age_Group'] = pd.cut(df['Age'], bins, labels=gp_labels, right=False)
# 使用 groupby() 和 apply() 方法
print(df['Age'].groupby(df['Age_Group']).apply(stats).unstack())
首先,我們匯入了 Pandas 函式庫並建立了一個包含年齡資料的 DataFrame。接著,定義了一個名為 stats
的函式,用於計算每個組的 count、min、max 和 mean 統計值。然後,使用 pd.cut()
方法將年齡資料分割到不同的區間,並使用 right=False
引數確保區間左閉右開。groupby()
方法根據新的 Age_Group
欄位進行分組,apply()
方法將 stats
函式應用於每個組,最後 unstack()
方法重新調整結果的形狀,使其更易於閲讀。
graph LR B[B] A["定義統計函式 stats"] --> B{"定義區間和標籤"} B --> C["使用 pd.cut() 分割資料"] C --> D["使用 groupby() 分組"] D --> E["使用 apply() 應用統計函式"] E --> F["使用 unstack() 重新調整結果"]
這個流程圖清晰地展示了資料處理的步驟:定義統計函式、定義區間和標籤、使用 pd.cut()
分割資料、使用 groupby()
分組、應用統計函式以及重新調整結果。
透過以上方法,我們可以有效地利用 Pandas 的 groupby()
方法對資料進行分組和統計分析,即使是連續數值欄位也能輕鬆處理。 pd.cut()
方法的應用,讓我們能夠更精細地控制分組的區間,從而更好地理解資料的分佈和趨勢。
在資料分析中,Pandas 的 groupby()
方法提供了一個強大與靈活的工具,可以讓我們根據不同的需求對資料進行分組和分析。透過結合不同的聚合函式和過濾條件,我們可以從資料中提取有價值的資訊。這個技巧在實際資料分析中非常有用,可以幫助我們更好地理解資料的分佈和趨勢。