在數據分析的世界裏,我們常常需要把不同來源的數據“組合”起來,比如把用戶信息表和訂單表合併分析,或者把不同月份的銷售數據拼接成一個大表。pandas 提供了 merge 和 concat 兩個超級實用的工具,能幫我們輕鬆完成這些操作。今天我們就用最簡單的方式,一步步掌握這兩個基礎操作,新手也能快速上手!
一、爲什麼需要數據合併?¶
想象一下,你有兩個表格:一個是“學生基本信息表”(包含姓名、年齡),另一個是“學生成績表”(包含姓名、科目、分數)。如果想分析每個學生的成績和年齡,就需要把這兩個表“合併”起來。pandas 的 merge 和 concat 就是幹這個的!
二、concat:簡單拼接,適合“加行”或“加列”¶
concat 就像“把兩張紙上下或左右粘在一起”,不需要關聯鍵,直接按順序拼接。
1. 基本語法¶
pd.concat(objs, axis=0, ignore_index=False)
objs:要拼接的 DataFrame 列表(比如[df1, df2])axis=0:默認“上下拼接”(行方向);axis=1:“左右拼接”(列方向)ignore_index=True:重置索引(避免拼接後索引重複,新手必看!)
2. 行方向拼接(上下拼接)¶
場景:把兩個結構相同的表按行合併(比如不同月份的銷售數據)。
示例:
import pandas as pd
# 創建兩個簡單的 DataFrame
df1 = pd.DataFrame({
'姓名': ['張三', '李四'],
'年齡': [20, 21]
})
df2 = pd.DataFrame({
'姓名': ['王五', '趙六'],
'年齡': [22, 23]
})
# 上下拼接(默認 axis=0)
result_row = pd.concat([df1, df2])
print("不重置索引的拼接結果:")
print(result_row)
# 重置索引(推薦!避免索引重複)
result_row_reset = pd.concat([df1, df2], ignore_index=True)
print("\n重置索引後的拼接結果:")
print(result_row_reset)
輸出對比:
- 不重置索引時,結果會保留原索引(0,1,0,1)
- 重置索引後,索引會變成 0,1,2,3(更清晰)
3. 列方向拼接(左右拼接)¶
場景:把兩個結構不同但有共同“行標識”的表按列合併(比如學生信息表+成績表)。
示例:
# 新增一個成績表
score = pd.DataFrame({
'科目': ['數學', '語文'],
'分數': [90, 85]
})
# 左右拼接(axis=1)
result_col = pd.concat([df1, score], axis=1)
print("\n列方向拼接結果:")
print(result_col)
輸出:
姓名 年齡 科目 分數
0 張三 20 數學 90
1 李四 21 語文 85
(注意:這裏 df1 和 score 行數不同,拼接後會自動補 NaN 嗎?不會! 因爲列拼接要求行數必須相同,否則會報錯。如果行數不同,會用 NaN 填充嗎?測試發現,如果行數不同,比如 df1 有 2 行,score 有 2 行纔可以。如果行數不同,會報錯。所以列拼接通常要求行數量一致。)
三、merge:基於“鍵”合併,像 SQL JOIN¶
merge 就像“按身份證號匹配兩個人的信息”,需要共同的“鍵”(比如姓名、ID)來關聯,類似 SQL 的 JOIN 操作。
1. 基本語法¶
pd.merge(left, right, on=None, how='inner', left_on=None, right_on=None)
left/right:要合併的兩個 DataFrameon:共同的列名(如果兩個表的鍵名相同)how:合併方式(inner/left/right/outer,默認inner)left_on/right_on:如果鍵名不同,用這兩個參數分別指定(比如左表用id,右表用student_id)
2. 核心合併方式(以“學生表”和“成績表”爲例)¶
假設我們有:
- 學生表(student):包含 student_id(學號)、姓名、年齡
- 成績表(score):包含 student_id(學號)、科目、分數
# 創建示例數據
student = pd.DataFrame({
'student_id': [1, 2, 3],
'姓名': ['張三', '李四', '王五'],
'年齡': [20, 21, 22]
})
score = pd.DataFrame({
'student_id': [1, 2, 4], # 注意:4號學生在學生表中不存在
'科目': ['數學', '語文', '英語'],
'分數': [90, 85, 95]
})
(1)內連接(how='inner',默認)¶
效果:只保留兩個表都有的“共同鍵”(student_id)對應的行。
inner_merge = pd.merge(student, score, on='student_id')
print("內連接結果:")
print(inner_merge)
輸出:
student_id 姓名 年齡 科目 分數
0 1 張三 20 數學 90
1 2 李四 21 語文 85
- 結果只保留
student_id=1和2(學生表中 3 號、成績表中 4 號被排除)
(2)左連接(how='left')¶
效果:保留左表(student)的所有行,右表(score)沒有匹配的用 NaN 填充。
left_merge = pd.merge(student, score, on='student_id', how='left')
print("\n左連接結果:")
print(left_merge)
輸出:
student_id 姓名 年齡 科目 分數
0 1 張三 20 數學 90.0
1 2 李四 21 語文 85.0
2 3 王五 22 NaN NaN
- 學生表的 3 號學生在成績表中沒有數據,所以科目和分數列填
NaN
(3)右連接(how='right')¶
效果:保留右表(score)的所有行,左表(student)沒有匹配的用 NaN 填充。
right_merge = pd.merge(student, score, on='student_id', how='right')
print("\n右連接結果:")
print(right_merge)
輸出:
student_id 姓名 年齡 科目 分數
0 1 張三 20.0 數學 90
1 2 李四 21.0 語文 85
2 4 NaN NaN 英語 95
- 成績表的 4 號學生在學生表中沒有數據,所以姓名和年齡列填
NaN
(4)外連接(how='outer')¶
效果:保留兩個表的所有行,沒有匹配的都用 NaN 填充。
outer_merge = pd.merge(student, score, on='student_id', how='outer')
print("\n外連接結果:")
print(outer_merge)
輸出:
student_id 姓名 年齡 科目 分數
0 1 張三 20.0 數學 90.0
1 2 李四 21.0 語文 85.0
2 3 王五 22.0 NaN NaN
3 4 NaN NaN 英語 95.0
(5)鍵名不同時怎麼辦?¶
如果兩個表的鍵名不一樣(比如左表用 id,右表用 user_id),需要用 left_on 和 right_on 指定。
# 假設學生表的鍵名是 id,成績表的鍵名是 student_id
student_renamed = student.rename(columns={'student_id': 'id'})
score_renamed = score.rename(columns={'student_id': 'student_id'})
diff_keys_merge = pd.merge(
student_renamed,
score_renamed,
left_on='id', # 左表的鍵列名
right_on='student_id' # 右表的鍵列名
)
print("\n鍵名不同時的合併結果:")
print(diff_keys_merge)
輸出:
id 姓名 年齡 student_id 科目 分數
0 1 張三 20 1 數學 90
1 2 李四 21 2 語文 85
四、總結:merge vs concat 怎麼選?¶
| 方法 | 適用場景 | 關鍵參數 |
|---|---|---|
| concat | 簡單拼接(無關聯鍵),或“加行/加列” | axis(0=行,1=列)、ignore_index |
| merge | 有共同鍵的表合併(類似 SQL JOIN) | how(內/左/右/外)、on/left_on/right_on |
五、新手必記關鍵點¶
-
concat:
- 無關聯鍵,直接拼接;
- 行拼接(axis=0):行數增加,列數不變;
- 列拼接(axis=1):列數增加,行數必須一致;
- 用ignore_index=True避免索引重複。 -
merge:
- 有關聯鍵,按鍵匹配;
-how參數控制合併方式(內/左/右/外);
- 鍵名不同時用left_on/right_on指定。
多動手練習吧!從簡單的小例子開始,慢慢嘗試不同的合併方式,很快就能熟練掌握啦~