在資料分析領域,資料合併是一項不可或缺的技能。資料通常分散在不同的來源,格式也可能各異,需要我們有效地將它們整合起來才能進行分析。Python 的 Pandas 函式庫提供了強大的資料合併功能,讓我得以輕鬆應對各種資料整合的挑戰。

我經常使用 Pandas 的 concat()merge() 方法來合併 DataFrame。concat() 就像拼接積木一樣,可以將 DataFrame 沿著行或列方向連線起來,實作聯集、交集等操作。merge() 則更像是資料函式庫中的 JOIN 操作,可以根據指定的鍵值將不同的 DataFrame 關聯起來。

基本資料合併示例

以下,我將用一些實際案例來示範如何使用這些方法。

首先,我們建立兩個 DataFrame,employeessalaries,並使用 ID 作為共同鍵值:

# 匯入必要的函式庫
import pandas as pd
import numpy as np

# 建立 employees DataFrame,包含員工基本資訊
employees = pd.DataFrame({
    'ID': [929, 446, 228, 299, 442, 321, 321, 882],
    'Name': ['Gunter', 'Harbinger', 'Benito', 'Rudelich', 'Sirignano', 'Morrison', 'Morrison', 'Onieda'],
    'Gender': ['M', 'M', 'F', 'M', 'F', 'M', 'M', 'F'],
    'Dept': ['Mfg', 'Mfg', 'Mfg', 'Sales', 'Admin', 'Sales', 'Sales', 'Admin']
})

# 建立 salaries DataFrame,包含員工薪資資訊
salaries = pd.DataFrame({
    'ID': [929, 446, 228, 299, 442, 871],
    'Salary': [45650, 51290, 62000, 39800, 44345, 70000]
})

# 顯示建立的 DataFrame
print("Employees DataFrame:\n", employees)
print("\nSalaries DataFrame:\n", salaries)

這段程式碼首先匯入了 Pandas 和 NumPy 函式庫。然後,分別使用字典建立了 employeessalaries 兩個 DataFrame,包含員工的 ID、姓名、性別、部門和薪資等資訊。最後,將兩個 DataFrame 輸出到螢幕。

值得注意的是,employees DataFrame 中,ID 為 321 的員工 Morrison 出現了兩次,這在實際資料中很常見,可能是同名同姓或者資料錄入錯誤。salaries DataFrame 中,ID 為 871 的員工在 employees DataFrame 中沒有對應的記錄,這也可能是資料不完整造成的。

Pandas 的不同合併方法

接下來,我們將使用不同的合併方法來整合這兩個 DataFrame。

# 使用 merge() 進行內連線(僅保留共同ID的資料)
merged_inner = pd.merge(employees, salaries, on='ID', how='inner')
print("\nInner Join:\n", merged_inner)

# 使用 merge() 進行左連線(保留所有employees資料)
merged_left = pd.merge(employees, salaries, on='ID', how='left')
print("\nLeft Join:\n", merged_left)

# 使用 merge() 進行右連線(保留所有salaries資料)
merged_right = pd.merge(employees, salaries, on='ID', how='right')
print("\nRight Join:\n", merged_right)

# 使用 merge() 進行外連線(保留所有資料)
merged_outer = pd.merge(employees, salaries, on='ID', how='outer')
print("\nOuter Join:\n", merged_outer)

這段程式碼示範了 merge() 方法的四種連線方式:內連線 (inner)、左連線 (left)、右連線 (right) 和外連線 (outer)。

  • 內連線: 只保留兩個 DataFrame 中 ID 都存在的資料。
  • 左連線: 保留 employees DataFrame 中的所有資料,並將 salaries DataFrame 中比對的資料連線起來。如果 employees DataFrame 中的 IDsalaries DataFrame 中不存在,則薪資欄位會顯示為 NaN
  • 右連線: 保留 salaries DataFrame 中的所有資料,並將 employees DataFrame 中比對的資料連線起來。如果 salaries DataFrame 中的 IDemployees DataFrame 中不存在,則其他欄位會顯示為 NaN
  • 外連線: 保留兩個 DataFrame 中的所有資料,並將比對的資料連線起來。如果某個 ID 只在其中一個 DataFrame 中存在,則另一個 DataFrame 對應的欄位會顯示為 NaN

Pandas 的 concat() 方法

除了 merge(),另一個常用的合併方法是 concat():

# 使用 concat() 沿著列方向連線(垂直堆積疊)
concatenated_rows = pd.concat([employees, employees], ignore_index=True)
print("\nConcatenated Rows:\n", concatenated_rows)

# 使用 concat() 沿著列方向連線,並指定 keys 便於識別來源
concatenated_rows_keys = pd.concat([employees, employees], keys=['df1', 'df2'])
print("\nConcatenated Rows with Keys:\n", concatenated_rows_keys)

這段程式碼示範了 concat() 方法如何沿著列方向連線 DataFrame。ignore_index=True 會重新生成索引,keys 引數可以為每個 DataFrame 增加一個標籤,方便區分資料來源。

進階 Pivot Table 應用

pivot_table() 是另一個強大的資料重塑工具:

# 建立範例銷售資料
sales = pd.DataFrame({
    'Year': [2022, 2022, 2022, 2023, 2023, 2023],
    'ProductLine': ['Classic Cars', 'Motorcycles', 'Trucks and Buses', 'Classic Cars', 'Motorcycles', 'Trucks and Buses'],
    'Territory': ['APAC', 'EMEA', 'NA', 'APAC', 'EMEA', 'NA'],
    'Amount': [1000, 2000, 3000, 4000, 5000, 6000],
    'Quantity': [10, 20, 30, 40, 50, 60]
})

# 漸漬複雜樞紐表,包含多個值和不同的聚合函式
pivot_table = pd.pivot_table(sales, values=['Amount', 'Quantity'],
                           columns='Territory',
                           index=['Year', 'ProductLine'],
                           fill_value=0,
                           aggfunc={'Amount': np.mean, 'Quantity': np.sum},
                           margins=True)

print("\nPivot Table:\n", pivot_table)

# 按年份和產品線彙總每個地區的銷售額
sales_by_year = pd.pivot_table(sales, values='Amount',
                               columns='Territory',
                               index=['Year', 'ProductLine'],
                               fill_value=0,
                               aggfunc=np.sum)

print("\nSales by Year:\n", sales_by_year)

這段程式碼示範了 pivot_table() 的一些進階用法。第一個 pivot_table() 使用了多個值欄位 (AmountQuantity),並對它們應用了不同的聚合函式 (np.meannp.sum)。fill_value=0 將缺失值填充為 0,margins=True 增加了行列總計。第二個 pivot_table() 根據年份和產品線彙總了每個地區的銷售額。

透過這些案例,我們可以看到 Pandas 提供了豐富的資料合併和處理功能,可以幫助我們高效地整合和分析資料。

選擇哪種合併方法取決於您的具體需求。理解每種方法的特性,才能在資料分析中做出最佳選擇。

資料合併流程圖示

以下流程圖展示了不同合併方法的應用場景:

  graph LR
    D[D]
    H[H]
    A[Employees DataFrame] --> B(Merge)
    C[Salaries DataFrame] --> B
    B --> D{Merged DataFrame}
    E[Employees DataFrame] --> F(Concat)
    G[Employees DataFrame] --> F
    F --> H{Concatenated DataFrame}
    I[Sales DataFrame] --> J{Pivot Table}

實際應用:尋找未比對的資料

以下示例展示如何找出右表中未比對的鍵值:

# 建立範例資料進行未比對資料示範
import pandas as pd

# 建立左表資料(員工基本資料)
left = pd.DataFrame({'ID': [929, 446, 228, 299, 442, 321, 321, 882],
                   'Name': ['Gunter', 'Harbinger', 'Benito', 'Rudelich', 'Sirignano', 'Morrison', 'Morrison', 'Onieda'],
                   'Gender': ['M', 'M', 'F', 'M', 'F', 'M', 'M', 'F'],
                   'Dept': ['Mfg', 'Mfg', 'Mfg', 'Sales', 'Admin', 'Sales', 'Sales', 'Admin'],
                   'Salary': [45650, 51290, 62000, 39800, 44345, None, None, None]})

# 建立右表資料(薪資資料)
right = pd.DataFrame({'ID': [929, 446, 228, 299, 442, 871],
                    'Salary': [45650, 51290, 62000, 39800, 44345, 70000]})

# 執行 RIGHT JOIN 並使用 indicator 參數來標記資料來源
merged_df = pd.merge(left, right, on='ID', how='right', indicator=True)

# 過濾出僅出現在右表的資料(未比對的資料)
right_only_df = merged_df[merged_df['_merge'] == 'right_only']

# 顯示未比對的資料
print("未比對的資料:")
print(right_only_df)

這段程式碼首先建立了兩個 DataFrame,leftright,用於模擬實際資料。接著,使用 pd.merge() 函式進行 RIGHT JOIN 操作。how='right' 引數指定了 RIGHT JOINindicator=True 引數則會新增一個名為 _merge 的欄位,用於指示每一列的資料來源。最後,透過篩選 _merge 欄位的值為 'right_only',即可得到只存在於 right DataFrame 中的資料列,也就是未比對的鍵值。

SAS 中的等效操作

對於同樣需求,在 SAS 中的操作方式:

/* 先對資料進行排序 */
proc sort data=left;
by id;
run;

proc sort data=right;
by id;
run;

/* 執行合併並找出未比對的鍵值 */
data r_join_nmk;
merge left(in=l) right(in=r);
by id;
if r=1 and l=0 then output;
run;

/* 顯示結果 */
proc print data=r_join_nmk;
run;

在 SAS 中,我們首先使用 PROC SORTleftright 兩個資料集按照 ID 欄位進行排序。排序是 MERGE 操作的前提條件。接著,使用 DATA 步驟和 MERGE 陳述式進行 RIGHT JOINin=lin=r 選項分別建立了布林變數 lr,用於指示目前的觀察值是否來自 leftright 資料集。if r=1 and l=0 條件判斷篩選出只存在於 right 資料集(r=1)與不存在於 left 資料集(l=0)的資料列,也就是未比對的鍵值。最後,使用 PROC PRINT 顯示結果。

效能最佳化策略

高效能 JOIN 策略的選擇取決於資料集的大小、資料結構和具體的應用場景。理解不同 JOIN 方法的特性,並根據實際情況選擇合適的策略,才能最大程度地提升資料處理效率。

在資料量較大的情況下,索引的使用可以顯著提升 JOIN 操作的效能。在 pandas 中,可以利用 set_index() 方法將 JOIN 鍵設定為索引,從而加快合併速度。在 SAS 中,可以建立索引來最佳化 MERGE 操作的效能。

此外,針對不同的資料函式庫系統,還可以選擇使用特定的 JOIN 最佳化技巧,例如使用雜湊 JOIN 或排序合併 JOIN 等。

總之,選擇合適的 JOIN 策略和最佳化技巧,對於提升資料處理效能至關重要。

資料更新案例

在資料分析領域,資料合併是一項基礎與重要的技能。我經常需要合併來自不同來源的資料,例如使用者資訊、產品銷售記錄等等。不同的程式語言和工具提供了各種資料合併方法,其中 JOIN 操作是最常用的技術之一。本部分將深入比較 Python 的 Pandas 函式庫和 SAS 中的 JOIN 技術,並分享一些最佳實踐。

RIGHT JOIN:尋找未比對的資料

RIGHT JOIN 是一種特殊的合併方式,它保留右表的所有資料列,並比對左表中符合條件的資料列。如果左表中沒有比對的資料列,則用 NaN 填充。這種方法在我處理資料驗證和異常檢測時非常有用,例如找出未完成訂單的使用者,或識別未參與活動的客戶。

以下程式碼展示瞭如何在 Pandas 中使用 RIGHT JOIN

# 在Pandas中使用RIGHT JOIN示例
import pandas as pd

# 建立兩個測試資料框
left = pd.DataFrame({'ID': ['01', '02', '03'], 'Name': ['Alice', 'Bob', 'Charlie']})
right = pd.DataFrame({'ID': ['02', '03', '04'], 'Dept': ['Sales', 'Marketing', 'HR']})

# 執行RIGHT JOIN操作
merged_df = pd.merge(left, right, on='ID', how='right')

# 顯示合併結果
print("RIGHT JOIN結果:")
print(merged_df)

這段程式碼使用 pd.merge() 函式進行 RIGHT JOINon='ID' 指定合併的鍵值欄位為 ‘ID’,how='right' 指定合併方式為 RIGHT JOIN

在 SAS 中,也可以使用 SQL 執行類別似操作:

/* 在SAS中使用PROC SQL執行RIGHT JOIN */
proc sql;
create table merged_table as
select coalesce(left.ID, right.ID) as ID, left.Name, right.Dept
from left
right join right on left.ID = right.ID;
quit;

在 SAS 中,我們使用 PROC SQL 執行 RIGHT JOINcoalesce 函式用於處理左表中缺失的 ID 值。

LEFT JOIN 與 OUTER JOIN:全方位資料合併

LEFT JOIN 保留左表的所有資料列,而 OUTER JOIN 則保留左右兩表的所有資料列。這兩種方法適用於需要保留所有資訊的場景,例如分析使用者行為或產品銷售趨勢。

Pandaspd.merge() 函式同樣支援 LEFT JOINOUTER JOIN,只需將 how 引數分別設定為 'left''outer' 即可。

SAS 中則需要調整 PROC SQL 中的 JOIN 型別。

效能最佳化:索引合併與資料驗證

在處理大型資料集時,效能最佳化至關重要。Pandas 的 join() 方法提供根據索引的合併,效率更高。此外,資料驗證也是確保合併結果準確性的關鍵步驟。

# 透過索引合併提高效能
# 建立兩個以索引為鍵的DataFrame
left = pd.DataFrame({'Name': ['Alice', 'Bob', 'Charlie']}, index=['01', '02', '03'])
right = pd.DataFrame({'Dept': ['Sales', 'Marketing', 'HR']}, index=['02', '03', '04'])

# 使用join方法根據索引合併
merged_df = left.join(right, how='outer')

# 顯示合併結果
print("根據索引的OUTER JOIN:")
print(merged_df)

此程式碼示範了 Pandas 根據索引的 OUTER JOIN

在 SAS 中,可以使用 PROC FREQPROC SQL 進行資料驗證,例如檢查鍵值的唯一性。

資料更新:Pandas 的 update 方法

除了合併資料,Pandas 的 update 方法可以根據索引或鍵值欄位更新 DataFrame 的值。這在我需要更新資料函式庫中的記錄時非常有用。

# 使用update方法更新DataFrame
# 建立原始DataFrame
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})

# 建立包含更新值的DataFrame
new_df = pd.DataFrame({'A': [7, 8], 'B': [9, 10]}, index=[0, 2])

# 使用update方法更新值
df.update(new_df)

# 顯示更新後的DataFrame
print("更新後的DataFrame:")
print(df)

這段程式碼使用 new_df 更新 df 的值。

資料合併決策流程

以下流程圖說明了不同情境下的資料合併方法選擇:

  graph LR
    B[B]
    D[D]
    A[資料準備] --> B{需要更新資料?};
    B -- Yes --> C[使用 update 方法];
    B -- No --> D{根據索引合併?};
    D -- Yes --> E[使用 join 方法];
    D -- No --> F[使用 merge 方法];
    C --> G[資料更新完成];
    E --> G;
    F --> G;

透過熟練運用 Pandas 和 SAS 中的 JOINupdate 方法,並結合效能最佳化和資料驗證的技巧,我們可以更有效率地處理資料合併任務,並確保資料的準確性和完整性。

本文探討了資料合併中的各種技巧,從基本的合併方法到進階的效能最佳化,希望能幫助讀者在實際資料分析中更得心應手。