五個(gè)案例快速熟悉 Pandas 常用操作
Pandas是Python生態(tài)系統(tǒng)中用于數(shù)據(jù)處理和分析的核心庫(kù)。它構(gòu)建在NumPy之上,提供了高性能、易于使用的數(shù)據(jù)結(jié)構(gòu)(主要是Series一維數(shù)據(jù)和DataFrame二維數(shù)據(jù))和數(shù)據(jù)分析工具。無(wú)論是數(shù)據(jù)清洗、轉(zhuǎn)換、合并還是可視化前的準(zhǔn)備,Pandas都是數(shù)據(jù)科學(xué)家的得力助手。
案例一:數(shù)據(jù)加載與查看
(1) 場(chǎng)景描述
數(shù)據(jù)分析的第一步通常是從外部文件(如CSV、Excel)加載數(shù)據(jù),并快速查看數(shù)據(jù)的基本信息,如前幾行、后幾行、整體結(jié)構(gòu)等。
# 導(dǎo)入pandas庫(kù),通常簡(jiǎn)寫(xiě)為pd
import pandas as pd
import io # 用于在內(nèi)存中模擬文件
# ---- 1. 數(shù)據(jù)加載 ----
# 假設(shè)的CSV數(shù)據(jù)內(nèi)容 (如果在本地有文件,請(qǐng)使用 pd.read_csv('students.csv'))
csv_data = """StudentID,Name,Age,Major,GPA
1001,Alice,21,Computer Science,3.8
1002,Bob,22,Physics,3.5
1003,Charlie,20,Mathematics,3.9
1004,David,23,Computer Science,3.7
1005,Eve,21,Engineering,3.6
"""
# 使用 io.StringIO 在內(nèi)存中模擬一個(gè)CSV文件對(duì)象
# 然后使用 pandas 讀取這個(gè)模擬文件
# 如果有實(shí)際文件 'students.csv',直接用 df = pd.read_csv('students.csv') 即可
df = pd.read_csv(io.StringIO(csv_data))
print("--- 數(shù)據(jù)加載成功 ---")
# 打印整個(gè)DataFrame (對(duì)于大數(shù)據(jù)集,通常不建議直接打印整個(gè)df)
# print(df)
# ---- 2. 數(shù)據(jù)基本查看 ----
# 查看數(shù)據(jù)的前5行 (默認(rèn)n=5)
print("\n--- 查看前5行 (head) ---")
print(df.head())
# 查看數(shù)據(jù)的后3行
print("\n--- 查看后3行 (tail) ---")
print(df.tail(3))
# 查看DataFrame的索引、列名和數(shù)據(jù)類(lèi)型等信息
print("\n--- 查看基本信息 (info) ---")
df.info()
# 查看數(shù)值型列的描述性統(tǒng)計(jì)信息(計(jì)數(shù)、均值、標(biāo)準(zhǔn)差、最小值、四分位數(shù)、最大值)
print("\n--- 查看描述性統(tǒng)計(jì) (describe) ---")
print(df.describe())
# 查看DataFrame的維度(行數(shù), 列數(shù))
print("\n--- 查看數(shù)據(jù)維度 (shape) ---")
print(df.shape)
# 查看所有列名
print("\n--- 查看列名 (columns) ---")
print(df.columns)
# 查看每一列的數(shù)據(jù)類(lèi)型
print("\n--- 查看數(shù)據(jù)類(lèi)型 (dtypes) ---")
print(df.dtypes)
(2) 代碼注釋
- pd.read_csv(): 這是Pandas用于讀取CSV文件的核心函數(shù)。它可以直接讀取文件路徑或類(lèi)文件對(duì)象。
- df.head(n): 返回DataFrame的前n行,默認(rèn)為5。用于快速預(yù)覽數(shù)據(jù)。
- df.tail(n): 返回DataFrame的后n行,默認(rèn)為5。用于檢查數(shù)據(jù)結(jié)尾。
- df.info(): 提供DataFrame的緊湊摘要,包括索引類(lèi)型、列名、非空值數(shù)量和內(nèi)存使用情況。非常適合快速了解數(shù)據(jù)概況和類(lèi)型。
- df.describe(): 生成描述性統(tǒng)計(jì)數(shù)據(jù),主要針對(duì)數(shù)值類(lèi)型的列。對(duì)于非數(shù)值列,可以加include='object'或include='all'。
- df.shape: 返回一個(gè)元組,表示DataFrame的維度(行數(shù),列數(shù))。
- df.columns: 返回包含所有列名的索引對(duì)象。
- df.dtypes: 返回一個(gè)Series,其中包含每列的數(shù)據(jù)類(lèi)型。
案例二:數(shù)據(jù)選擇與過(guò)濾
(1) 場(chǎng)景描述
在數(shù)據(jù)分析中,我們經(jīng)常需要根據(jù)特定條件選擇數(shù)據(jù)的子集,例如選擇特定的列、或滿(mǎn)足某些條件的行。
(2) 使用數(shù)據(jù)
我們繼續(xù)使用上一個(gè)案例中加載的 df (學(xué)生數(shù)據(jù))。
(3) 代碼實(shí)現(xiàn)
# 繼續(xù)使用上一個(gè)案例創(chuàng)建的 df
print("--- 原始數(shù)據(jù) ---")
print(df)
# ---- 1. 選擇列 ----
# 選擇單列 (返回一個(gè) Series)
print("\n--- 選擇 'Name' 列 ---")
name_series = df['Name']
print(type(name_series)) # 輸出 <class 'pandas.core.series.Series'>
print(name_series)
# 選擇多列 (返回一個(gè)新的 DataFrame)
print("\n--- 選擇 'Name' 和 'GPA' 列 ---")
name_gpa_df = df[['Name', 'GPA']] # 注意這里用的是雙層方括號(hào)
print(type(name_gpa_df)) # 輸出 <class 'pandas.core.frame.DataFrame'>
print(name_gpa_df)
# ---- 2. 選擇行 (基于標(biāo)簽 loc 和 位置 iloc) ----
# 使用 .loc 按標(biāo)簽(索引名)選擇行
# DataFrame默認(rèn)索引是0, 1, 2... 此時(shí)loc和iloc在選擇行時(shí)表現(xiàn)類(lèi)似
print("\n--- 使用 loc 選擇索引為 1 的行 ---")
row_1_loc = df.loc[1] # 索引標(biāo)簽為 1
print(row_1_loc)
# 使用 .iloc 按整數(shù)位置選擇行 (從0開(kāi)始)
print("\n--- 使用 iloc 選擇第 3 行 (位置為 2) ---")
row_3_iloc = df.iloc[2] # 第3行的位置是2
print(row_3_iloc)
# 選擇連續(xù)多行
print("\n--- 使用 iloc 選擇第 2 到第 4 行 (位置 1 到 3) ---")
rows_1_to_3 = df.iloc[1:4] # 不包括位置4
print(rows_1_to_3)
# ---- 3. 選擇行和列 ----
# 使用 loc 選擇特定行和列
print("\n--- 使用 loc 選擇索引為 0 和 2 的行的 'Name' 和 'Age' 列 ---")
subset_loc = df.loc[[0, 2], ['Name', 'Age']]
print(subset_loc)
# 使用 iloc 選擇特定行和列 (按位置)
# 選擇第1行(位置0)、第3行(位置2) 的 第2列(位置1)、第4列(位置3)
print("\n--- 使用 iloc 選擇特定行和列 (按位置) ---")
subset_iloc = df.iloc[[0, 2], [1, 3]] # 行位置0, 2; 列位置1 (Name), 3 (Major)
print(subset_iloc)
# ---- 4. 條件過(guò)濾 (布爾索引) ----
# 選擇 Age 大于 21 的學(xué)生
print("\n--- 選擇 Age > 21 的學(xué)生 ---")
older_students = df[df['Age'] > 21]
print(older_students)
# 選擇 專(zhuān)業(yè)為 'Computer Science' 的學(xué)生
print("\n--- 選擇專(zhuān)業(yè)為 'Computer Science' 的學(xué)生 ---")
cs_students = df[df['Major'] == 'Computer Science']
print(cs_students)
# 組合條件:選擇專(zhuān)業(yè)為 'Computer Science' 且 GPA 大于 3.7 的學(xué)生
print("\n--- 選擇專(zhuān)業(yè)為 'Computer Science' 且 GPA > 3.7 的學(xué)生 ---")
top_cs_students = df[(df['Major'] == 'Computer Science') & (df['GPA'] > 3.7)] # 使用 & (and), | (or)
print(top_cs_students)
(4) 代碼注釋
- df['ColumnName']: 選擇單列,返回 Pandas Series。
- df[['Col1', 'Col2']]: 使用列表選擇多列,返回 Pandas DataFrame。
- df.loc[row_label, col_label]: 基于標(biāo)簽(索引名和列名)進(jìn)行選擇。標(biāo)簽可以是單個(gè)標(biāo)簽、列表或切片。
- df.iloc[row_position, col_position]: 基于整數(shù)位置(從0開(kāi)始)進(jìn)行選擇。位置可以是單個(gè)整數(shù)、列表或切片。
- df[boolean_condition]: 這是布爾索引的核心。boolean_condition 通常是一個(gè)評(píng)估為布爾值(True/False)的 Series(例如 df['Age'] > 21)。Pandas會(huì)返回 boolean_condition 為 True 的所有行。
- & (與), | (或), ~ (非): 用于組合多個(gè)布爾條件。注意:必須使用 & 和 |,而不是 Python 的 and 和 or。每個(gè)條件需要用括號(hào)括起來(lái)。
案例三:處理缺失值
(1) 場(chǎng)景描述
真實(shí)世界的數(shù)據(jù)往往不完美,包含缺失值(通常表示為 NaN, Not a Number)。處理缺失值是數(shù)據(jù)清洗的關(guān)鍵步驟,常見(jiàn)策略包括刪除缺失值或填充缺失值。
(2) 準(zhǔn)備數(shù)據(jù)
我們創(chuàng)建一個(gè)包含缺失值的新DataFrame。
(3) 代碼實(shí)現(xiàn)
import pandas as pd
import numpy as np # NumPy 通常用于生成 NaN
# ---- 1. 創(chuàng)建包含缺失值的DataFrame ----
data_with_nan = {
'StudentID': [1001, 1002, 1003, 1004, 1005, 1006],
'Name': ['Alice', 'Bob', 'Charlie', 'David', np.nan, 'Frank'],
'Age': [21, 22, 20, np.nan, 21, 22],
'GPA': [3.8, 3.5, 3.9, 3.7, np.nan, np.nan]
}
df_nan = pd.DataFrame(data_with_nan)
print("--- 包含缺失值的原始數(shù)據(jù) ---")
print(df_nan)
# ---- 2. 檢測(cè)缺失值 ----
# 檢查整個(gè)DataFrame是否有缺失值 (返回布爾型DataFrame)
print("\n--- 檢查缺失值 (isnull) ---")
print(df_nan.isnull()) # isnull() 和 isna() 等價(jià)
# 統(tǒng)計(jì)每列的缺失值數(shù)量
print("\n--- 統(tǒng)計(jì)每列的缺失值數(shù)量 ---")
print(df_nan.isnull().sum())
# 統(tǒng)計(jì)總的缺失值數(shù)量
print("\n--- 統(tǒng)計(jì)總?cè)笔е禂?shù)量 ---")
print(df_nan.isnull().sum().sum())
# ---- 3. 處理缺失值:刪除 ----
# 刪除任何包含缺失值的行 (dropna)
# axis=0 表示按行操作,how='any' 表示只要有一個(gè)NaN就刪除該行
print("\n--- 刪除包含NaN的行 (how='any') ---")
df_dropped_any = df_nan.dropna(axis=0, how='any') # 默認(rèn)行為
print(df_dropped_any)
# 刪除所有值都是缺失值的行 (how='all')
# 在這個(gè)例子中沒(méi)有這樣的行
# df_dropped_all = df_nan.dropna(axis=0, how='all')
# 刪除任何包含缺失值的列
# axis=1 表示按列操作
print("\n--- 刪除包含NaN的列 ---")
df_dropped_cols = df_nan.dropna(axis=1, how='any')
print(df_dropped_cols) # Name, Age, GPA列都會(huì)被刪除
# ---- 4. 處理缺失值:填充 ----
# 用一個(gè)特定值填充所有NaN
print("\n--- 用 0 填充所有 NaN ---")
df_filled_zero = df_nan.fillna(0)
print(df_filled_zero)
# 使用指定值填充特定列的NaN
# 例如,用 'Unknown' 填充 'Name' 列的NaN,用 'Age' 列的平均值填充 'Age' 的NaN
print("\n--- 分別填充不同列的 NaN ---")
# 先復(fù)制一份,避免修改原始 df_nan
df_filled_specific = df_nan.copy()
# 計(jì)算 Age 的平均值 (忽略NaN)
age_mean = df_filled_specific['Age'].mean()
print(f"Calculated mean age: {age_mean}")
# 填充 Name 列
df_filled_specific['Name'].fillna('Unknown', inplace=True) # inplace=True 直接修改原DataFrame
# 填充 Age 列
df_filled_specific['Age'].fillna(age_mean, inplace=True)
# 填充 GPA 列 (例如用中位數(shù))
gpa_median = df_filled_specific['GPA'].median()
print(f"Calculated median GPA: {gpa_median}")
df_filled_specific['GPA'].fillna(gpa_median, inplace=True)
print(df_filled_specific)
# 使用前向填充 (用前一個(gè)有效值填充)
print("\n--- 使用前向填充 (ffill) ---")
df_ffilled = df_nan.fillna(method='ffill') # or .ffill()
print(df_ffilled)
# 使用后向填充 (用后一個(gè)有效值填充)
print("\n--- 使用后向填充 (bfill) ---")
df_bfilled = df_nan.fillna(method='bfill') # or .bfill()
print(df_bfilled)
(4) 代碼注釋
- pd.DataFrame(): 用于創(chuàng)建DataFrame。
- df.isnull() / df.isna(): 返回一個(gè)與原DataFrame形狀相同的布爾DataFrame,True表示對(duì)應(yīng)位置是缺失值。
- df.isnull().sum(): 對(duì)布爾DataFrame按列求和,得到每列缺失值的數(shù)量。
- df.dropna(axis=0/1, how='any'/'all', subset=['col']): 刪除包含缺失值的行(axis=0)或列(axis=1)。
- how='any':只要有NaN就刪除。
- how='all':所有值都是NaN才刪除。
- subset:指定只在哪些列中檢查NaN。
- df.fillna(value, method='ffill'/'bfill', inplace=False): 填充缺失值。
- value: 可以是標(biāo)量(填充所有NaN),或是一個(gè)字典(指定每列用什么值填充)。
- method='ffill':前向填充。
- method='bfill':后向填充。
- inplace=True: 直接修改原DataFrame,而不是返回一個(gè)新對(duì)象。謹(jǐn)慎使用。
- df['column'].mean(), df['column'].median(), df['column'].mode()[0]: 常用于計(jì)算填充缺失值所需的統(tǒng)計(jì)量(均值、中位數(shù)、眾數(shù))。
案例四:數(shù)據(jù)分組與聚合
(1) 場(chǎng)景描述
分組聚合是數(shù)據(jù)分析中非常強(qiáng)大的功能,允許我們按照某些類(lèi)別對(duì)數(shù)據(jù)進(jìn)行分組,然后對(duì)每個(gè)組應(yīng)用聚合函數(shù)(如求和、計(jì)數(shù)、平均值等),從而提取有價(jià)值的洞察。
(2) 準(zhǔn)備數(shù)據(jù)
假設(shè)我們有以下銷(xiāo)售數(shù)據(jù):
import pandas as pd
# 銷(xiāo)售數(shù)據(jù)
sales_data = {
'Category': ['Electronics', 'Clothing', 'Electronics', 'Groceries', 'Clothing', 'Groceries', 'Electronics', 'Clothing'],
'Product': ['Laptop', 'T-Shirt', 'Phone', 'Apples', 'Jeans', 'Milk', 'Tablet', 'Jacket'],
'Sales': [1200, 25, 800, 5, 70, 3, 650, 150],
'Quantity': [1, 2, 1, 10, 1, 3, 1, 1]
}
df_sales = pd.DataFrame(sales_data)
print("--- 原始銷(xiāo)售數(shù)據(jù) ---")
print(df_sales)
(3) 代碼實(shí)現(xiàn)
# 繼續(xù)使用上面創(chuàng)建的 df_sales
# ---- 1. 按單列分組并聚合 ----
# 按 'Category' 分組,計(jì)算每個(gè)類(lèi)別的總銷(xiāo)售額
print("\n--- 按 Category 分組計(jì)算總銷(xiāo)售額 (sum) ---")
category_sales_sum = df_sales.groupby('Category')['Sales'].sum()
print(category_sales_sum)
print(type(category_sales_sum)) # 返回 Series
# 按 'Category' 分組,計(jì)算每個(gè)類(lèi)別的平均銷(xiāo)售額和總數(shù)量
# 如果對(duì)分組后的對(duì)象直接調(diào)用聚合函數(shù),會(huì)對(duì)所有數(shù)值列進(jìn)行計(jì)算
print("\n--- 按 Category 分組計(jì)算所有數(shù)值列的均值 (mean) ---")
category_mean = df_sales.groupby('Category').mean() # 計(jì)算 Sales 和 Quantity 的均值
print(category_mean)
print(type(category_mean)) # 返回 DataFrame
# 按 'Category' 分組,計(jì)算每個(gè)類(lèi)別有多少條記錄 (size 或 count)
print("\n--- 按 Category 分組計(jì)算記錄數(shù) (size) ---")
category_counts = df_sales.groupby('Category').size()
print(category_counts)
# 使用 count() - 會(huì)分別計(jì)算每列的非空記錄數(shù)
# print("\n--- 按 Category 分組計(jì)算記錄數(shù) (count) ---")
# category_counts_col = df_sales.groupby('Category').count()
# print(category_counts_col)
# ---- 2. 按多列分組 ----
# 按 'Category' 和 'Product' 分組 (雖然這里Product唯一,演示多級(jí)索引)
# 計(jì)算每個(gè)產(chǎn)品組的總銷(xiāo)售額 (在這個(gè)數(shù)據(jù)里,每個(gè)組只有一行)
print("\n--- 按 Category 和 Product 分組計(jì)算總銷(xiāo)售額 ---")
category_product_sales = df_sales.groupby(['Category', 'Product'])['Sales'].sum()
print(category_product_sales) # 結(jié)果是一個(gè)具有多級(jí)索引 (MultiIndex) 的 Series
# ---- 3. 使用 agg 進(jìn)行多種聚合 ----
# 對(duì)不同列應(yīng)用不同的聚合函數(shù),或者對(duì)同一列應(yīng)用多個(gè)聚合函數(shù)
print("\n--- 使用 agg 對(duì) Category 分組進(jìn)行多種聚合 ---")
agg_results = df_sales.groupby('Category').agg(
TotalSales=('Sales', 'sum'), # 計(jì)算 Sales 的總和,結(jié)果列名為 TotalSales
AverageSales=('Sales', 'mean'), # 計(jì)算 Sales 的平均值,結(jié)果列名為 AverageSales
TotalQuantity=('Quantity', 'sum'), # 計(jì)算 Quantity 的總和
ProductCount=('Product', 'count') # 計(jì)算每個(gè)類(lèi)別有多少個(gè)產(chǎn)品記錄
)
print(agg_results)
# 對(duì)同一列應(yīng)用多個(gè)聚合函數(shù)
print("\n--- 對(duì) Sales 列應(yīng)用多個(gè)聚合函數(shù) ---")
sales_agg = df_sales.groupby('Category')['Sales'].agg(['sum', 'mean', 'min', 'max', 'count'])
print(sales_agg)
(4) 代碼注釋
① df.groupby('ColumnName') 或 df.groupby(['Col1', 'Col2']): 創(chuàng)建一個(gè) GroupBy 對(duì)象,按指定的列(一個(gè)或多個(gè))對(duì) DataFrame 進(jìn)行分組。這本身不進(jìn)行計(jì)算,只是定義了分組規(guī)則。
② .sum(), .mean(), .median(), .min(), .max(), .count(), .size(), .std(), .var(): 這些是常用的聚合函數(shù),可以直接應(yīng)用在 GroupBy 對(duì)象上或選擇了特定列的 GroupBy 對(duì)象上。
③ .size(): 返回每個(gè)組的大小(行數(shù)),結(jié)果是 Series。
④ .count(): 返回每個(gè)組中每列的非空值的數(shù)量,結(jié)果是 DataFrame。
⑤ GroupBy_Object['TargetColumn']: 在分組后選擇要進(jìn)行聚合的列。
⑥ .agg(): 提供更靈活的聚合方式。
- 可以傳遞一個(gè)函數(shù)列表,如 ['sum', 'mean'],對(duì)選定的列應(yīng)用所有這些函數(shù)。
- 可以傳遞一個(gè)字典,如 {'Sales': 'sum', 'Quantity': 'mean'},對(duì)不同的列應(yīng)用不同的聚合函數(shù)。
- 可以使用命名聚合(如 TotalSales=('Sales', 'sum')),允許自定義輸出列名,語(yǔ)法為 NewColumnName = ('SourceColumnName', 'AggregationFunction')。這在 Pandas 較高版本中推薦使用。
案例五:數(shù)據(jù)合并與連接 (Bonus)
(1) 場(chǎng)景描述
在實(shí)際項(xiàng)目中,數(shù)據(jù)通常分散在多個(gè)表(DataFrame)中,需要將它們根據(jù)共同的鍵(key)合并或連接起來(lái)。
(2) 準(zhǔn)備數(shù)據(jù)
創(chuàng)建兩個(gè)簡(jiǎn)單的DataFrame用于演示合并。
import pandas as pd
# 第一個(gè)DataFrame: 員工信息
df_employees = pd.DataFrame({
'EmpID': [101, 102, 103, 104],
'Name': ['Alice', 'Bob', 'Charlie', 'David'],
'DepartmentID': [1, 2, 1, 3]
})
# 第二個(gè)DataFrame: 部門(mén)信息
df_departments = pd.DataFrame({
'DeptID': [1, 2, 3, 4],
'DepartmentName': ['HR', 'Engineering', 'Sales', 'Marketing'],
'Location': ['New York', 'San Francisco', 'New York', 'Chicago']
})
print("--- 員工信息 DataFrame ---")
print(df_employees)
print("\n--- 部門(mén)信息 DataFrame ---")
print(df_departments)
(3) 代碼實(shí)現(xiàn)
# ---- 1. 使用 merge 進(jìn)行合并 ----
# 內(nèi)連接 (Inner Join): 只保留兩個(gè)DataFrame中鍵都存在的行
# 需要指定左右DataFrame的連接鍵 (left_on, right_on)
print("\n--- 內(nèi)連接 (Inner Join) ---")
# EmpID 和 DeptID 是連接鍵,但名字不同
inner_merged_df = pd.merge(
df_employees,
df_departments,
left_on='DepartmentID', # df_employees 中的鍵
right_on='DeptID', # df_departments 中的鍵
how='inner' # 連接方式為內(nèi)連接
)
print(inner_merged_df)
# 注意 David (DepartmentID=3) 和 Sales (DeptID=3) 都被包含
# Marketing (DeptID=4) 沒(méi)有對(duì)應(yīng)的員工,HR (DeptID=1) 有兩個(gè)員工
# 左連接 (Left Join): 保留左邊DataFrame的所有行,以及右邊DataFrame匹配的行,不匹配的用NaN填充
print("\n--- 左連接 (Left Join) ---")
left_merged_df = pd.merge(
df_employees,
df_departments,
left_on='DepartmentID',
right_on='DeptID',
how='left'
)
print(left_merged_df)
# 所有員工都被保留。David (DepartmentID=3) 對(duì)應(yīng) Sales。
# 右連接 (Right Join): 保留右邊DataFrame的所有行,以及左邊DataFrame匹配的行,不匹配的用NaN填充
print("\n--- 右連接 (Right Join) ---")
right_merged_df = pd.merge(
df_employees,
df_departments,
left_on='DepartmentID',
right_on='DeptID',
how='right'
)
print(right_merged_df)
# 所有部門(mén)都被保留。Marketing (DeptID=4) 沒(méi)有對(duì)應(yīng)的員工,所以員工信息列為 NaN。
# 外連接 (Outer Join): 保留兩邊DataFrame的所有行,不匹配的用NaN填充
print("\n--- 外連接 (Outer Join) ---")
outer_merged_df = pd.merge(
df_employees,
df_departments,
left_on='DepartmentID',
right_on='DeptID',
how='outer'
)
print(outer_merged_df)
# 包含所有員工和所有部門(mén)。Marketing沒(méi)有員工,員工信息為NaN。
# ---- 2. 使用 concat 進(jìn)行連接 (堆疊) ----
# concat 主要用于沿某個(gè)軸(行或列)將多個(gè)DataFrame粘合在一起
# 假設(shè)有另一個(gè)員工 DataFrame
df_more_employees = pd.DataFrame({
'EmpID': [105, 106],
'Name': ['Eve', 'Frank'],
'DepartmentID': [2, 4] # Frank 在 Marketing 部門(mén)
})
print("\n--- 另一個(gè)員工 DataFrame ---")
print(df_more_employees)
# 按行堆疊 (axis=0, 默認(rèn))
print("\n--- 按行堆疊兩個(gè)員工 DataFrame (concat axis=0) ---")
all_employees_stacked = pd.concat([df_employees, df_more_employees], ignore_index=True)
# ignore_index=True 重新生成從0開(kāi)始的索引
print(all_employees_stacked)
# 按列連接 (axis=1) - 通常需要索引對(duì)齊
# 創(chuàng)建一個(gè)基于EmpID索引的DataFrame
df_salary = pd.DataFrame({
'EmpID': [101, 102, 103, 105],
'Salary': [70000, 80000, 75000, 90000]
}).set_index('EmpID')
df_employees_indexed = df_employees.set_index('EmpID')
print("\n--- 按列連接員工信息和薪水信息 (concat axis=1) ---")
# 需要先將 EmpID 設(shè)置為索引才能正確對(duì)齊
employee_salary_concat = pd.concat([df_employees_indexed, df_salary], axis=1)
print(employee_salary_concat)
# EmpID 104 (David) 沒(méi)有薪水信息,Salary 列為 NaN
# EmpID 105 (Eve) 有薪水但原始df_employees_indexed中沒(méi)有,所以Name和DepartmentID為NaN
# 注意:對(duì)于這種基于共同列的匹配連接,merge通常更直觀。
(4) 代碼注釋
① pd.merge(left_df, right_df, how='inner'/'left'/'right'/'outer', on='key_col', left_on='left_key', right_on='right_key'): 這是主要的合并函數(shù)。
- left_df, right_df: 要合并的兩個(gè)DataFrame。
- how: 指定合并方式(內(nèi)、左、右、外連接)。默認(rèn)為 'inner'。
- on: 如果連接鍵在兩個(gè)DataFrame中名稱(chēng)相同,可以用 on='key_col' 或 on=['key1', 'key2']。
- left_on, right_on: 如果連接鍵在兩個(gè)DataFrame中名稱(chēng)不同,需要分別指定。
② pd.concat([df1, df2, ...], axis=0/1, ignore_index=False, join='outer'/'inner'): 用于沿指定軸連接(堆疊)多個(gè)DataFrame。
- axis=0: 按行堆疊(默認(rèn))。列名不匹配的列會(huì)用NaN填充(除非join='inner')。
- axis=1: 按列并排連接?;谒饕龑?duì)齊。行索引不匹配的行會(huì)用NaN填充(除非join='inner')。
- ignore_index=True: 創(chuàng)建新的連續(xù)整數(shù)索引,忽略原始索引。
- join: 類(lèi)似merge的how,'outer'保留所有標(biāo)簽,'inner'只保留共有的標(biāo)簽。默認(rèn)為 'outer'。
總結(jié)
本文展示了Pandas在日常數(shù)據(jù)處理中最常用的一些功能。熟練掌握這些操作是進(jìn)行任何數(shù)據(jù)分析項(xiàng)目的基礎(chǔ)。當(dāng)然,Pandas的功能遠(yuǎn)不止于此,還包括時(shí)間序列處理、數(shù)據(jù)重塑、數(shù)據(jù)可視化接口等,值得進(jìn)一步深入探索。