การเชื่อมด้านซ้ายและด้านขวา
ดำเนินการเชื่อมด้านซ้ายและด้านขวาเพื่อเก็บแถวทั้งหมดจากตารางหนึ่ง พร้อมจับคู่ระเบียนจากอีกตาราง
การเชื่อมด้านซ้ายและด้านขวา เป็นบทเรียน Pandas & NumPy Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Pandas & NumPy Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Pandas & NumPy Academy มีบทเรียนทั้งหมด 4 บทเรียน
Join แบบไม่สมมาตร
Inner และ outer join ปฏิบัติต่อ DataFrame ทั้งสองชุดอย่างสมมาตร แต่บ่อยครั้งคุณต้องการคงระเบียนทั้งหมดจากตารางหนึ่งไว้ แล้วเพิ่มข้อมูลจากอีกตารางหนึ่งให้กับระเบียนเหล่านั้น นี่คือกรณีที่ left join และ right join มีประโยชน์ join แบบไม่สมมาตรเหล่านี้พบได้บ่อยมากในการวิเคราะห์ข้อมูล เช่น เก็บธุรกรรมทั้งหมดไว้ แล้วเพิ่มชื่อสินค้าเมื่อมีข้อมูล หรือเก็บผู้ใช้ทั้งหมดไว้ แล้วเพิ่มวันที่ซื้อครั้งล่าสุดหากมีข้อมูล
Left Join: คงแถวทั้งหมดฝั่งซ้าย
left join (how='left') จะเก็บทุกแถวจาก DataFrame ฝั่งซ้าย สำหรับแถวที่พบคีย์ตรงกันใน DataFrame ฝั่งขวา คอลัมน์ฝั่งขวาจะถูกเติมด้วยค่าที่ตรงกัน สำหรับแถวที่ไม่มีรายการตรงกัน คอลัมน์ฝั่งขวาจะถูกเติมด้วย NaN จำนวนแถวของผลลัพธ์จะเท่ากับจำนวนแถวของ DataFrame ฝั่งซ้ายเสมอ (หากไม่มีคีย์ซ้ำกัน)
import pandas as pd
orders = pd.DataFrame({
'order_id': [1, 2, 3, 4],
'customer_id': [101, 102, 101, 999],
'amount': [250, 80, 320, 150]
})
customers = pd.DataFrame({
'customer_id': [101, 102, 103],
'name': ['Alice', 'Bob', 'Carol']
})
result = pd.merge(orders, customers, on='customer_id', how='left')
print(result)
# All 4 orders kept; order with customer_id=999 gets NaN for nameโครงสร้างผลลัพธ์ของ Left Join
หลังจากทำ left join แถวจาก DataFrame ฝั่งซ้ายที่ไม่พบรายการตรงกันในฝั่งขวาจะมีค่า NaN ในทุกคอลัมน์ที่มาจากตารางฝั่งขวา คุณสามารถใช้คุณสมบัตินี้เพื่อระบุแถวที่ไม่ตรงกันด้วยตัวกรองบูลีนบนคอลัมน์ของตารางฝั่งขวา และนับจำนวนแถวฝั่งซ้ายที่ไม่มีรายการตรงกัน ซึ่งเป็นการตรวจสอบคุณภาพข้อมูลที่มีประโยชน์
result = pd.merge(orders, customers, on='customer_id', how='left')
print(result)
# order_id customer_id amount name
# 0 1 101 250 Alice
# 1 2 102 80 Bob
# 2 3 101 320 Alice
# 3 4 999 150 NaN <- no matching customer
# Count unmatched
unmatched = result['name'].isna().sum()
print(f'{unmatched} orders have no customer record')ควรใช้ Left Join เมื่อใด
left join เหมาะเมื่อDataFrame ฝั่งซ้ายเป็นตารางหลัก และตารางฝั่งขวาเป็นข้อมูลเสริม ตัวอย่างสถานการณ์ที่พบบ่อย ได้แก่ การเพิ่มข้อมูลจากตารางมิติให้กับตารางข้อเท็จจริง (คำสั่งซื้อ + ชื่อสินค้า) การเพิ่มข้อมูลกำกับที่อาจมีหรือไม่มีก็ได้ (ผู้ใช้ + ข้อมูลโปรไฟล์) หรือการคำนวณตัวชี้วัดให้กับทุกระเบียน แม้การค้นหาข้อมูลจะไม่สำเร็จ ในโค้ดวิเคราะห์ข้อมูลส่วนใหญ่ left join พบได้บ่อยกว่า right join มาก
# Realistic pattern: enrich all products with optional category data
products = pd.DataFrame({'sku': ['A1', 'B2', 'C3'], 'price': [10, 20, 15]})
categories = pd.DataFrame({'sku': ['A1', 'C3'], 'category': ['Tools', 'Home']})
# Keep all products; add category where available
enriched = pd.merge(products, categories, on='sku', how='left')
print(enriched)
# sku price category
# 0 A1 10 Tools
# 1 B2 20 NaN
# 2 C3 15 HomeRight Join: คงแถวทั้งหมดฝั่งขวา
right join (how='right') เป็นภาพสะท้อนของ left join กล่าวคือจะเก็บทุกแถวจาก DataFrame ฝั่งขวา และเติม NaN ให้กับคอลัมน์ของตารางฝั่งซ้ายเมื่อไม่มีรายการตรงกัน right join พบได้น้อยกว่า เพราะคุณสามารถให้ผลลัพธ์เดียวกันได้โดยสลับอาร์กิวเมนต์ของ DataFrame แล้วใช้ left join แทน ซึ่งอ่านเข้าใจได้ชัดเจนกว่า
# Right join: keep all customers, attach orders where they exist
result = pd.merge(orders, customers, on='customer_id', how='right')
print(result)
# All 3 customers appear; Carol (103) has NaN for order_id and amount
# Equivalent left join (swap arguments):
result2 = pd.merge(customers, orders, on='customer_id', how='left')
# Same data, just column order differsเปรียบเทียบ Join ทั้งสี่ประเภท
join ทั้งสี่ประเภทแตกต่างกันเพียงว่าจะแสดงแถวจากฝั่งที่ไม่มีรายการตรงกันหรือไม่ inner: เฉพาะแถวที่ตรงกัน outer: ทุกแถวจากทั้งสองฝั่ง left: ทุกแถวฝั่งซ้าย right: ทุกแถวฝั่งขวา สำหรับรายการที่ไม่ตรงกัน คอลัมน์จากฝั่งที่ไม่มีข้อมูลจะถูกเติมด้วย NaN การเลือกประเภทให้ถูกต้องมีความสำคัญอย่างยิ่ง เพื่อป้องกันการลบหรือทำซ้ำระเบียนโดยไม่มีการแจ้งเตือน
# Summary table
# how='inner' : rows in BOTH tables
# how='left' : ALL left rows + matched right
# how='right' : matched left + ALL right rows
# how='outer' : ALL left rows + ALL right rows
# Test each
for how in ['inner', 'left', 'right', 'outer']:
r = pd.merge(orders, customers, on='customer_id', how=how)
print(f'{how}: {len(r)} rows')การเติมค่า NaN ในผลลัพธ์ของ Left Join
หลังจากทำ left join แถวที่ไม่ตรงกันจะมีค่า NaN ในคอลัมน์ของตารางฝั่งขวา โดยทั่วไปคุณอาจต้องการเติมค่าเริ่มต้นที่เหมาะสมลงไป เช่น 'Unknown' สำหรับหมวดหมู่ที่ขาดหาย หรือ 0 สำหรับจำนวนที่ขาดหาย ให้ใช้ fillna() กับผลลัพธ์ หรือส่ง fill_value ในการดำเนินการทางคณิตศาสตร์ที่ทำต่อจาก join
result = pd.merge(products, categories, on='sku', how='left')
result['category'] = result['category'].fillna('Uncategorised')
print(result)
# sku price category
# 0 A1 10 Tools
# 1 B2 20 Uncategorised
# 2 C3 15 HomeLeft Anti-Join: แถวที่ไม่มีรายการตรงกัน
รูปแบบที่มีประโยชน์และไม่ได้รองรับโดยตรงผ่าน how คือ anti-join ซึ่งจะเก็บเฉพาะแถวฝั่งซ้ายที่ไม่มีรายการตรงกันในตารางฝั่งขวา ให้ดำเนินการโดยใช้ left join พร้อม indicator=True จากนั้นกรองค่า _merge == 'left_only' วิธีนี้เหมาะอย่างยิ่งสำหรับค้นหาระเบียนที่ไม่มีข้อมูลคู่ รายการใหม่ที่ไม่มีอยู่ในรายการอ้างอิง หรือธุรกรรมที่หายไปจากบัญชีแยกประเภท
# Anti-join: orders with no matching customer record
result = pd.merge(orders, customers, on='customer_id',
how='left', indicator=True)
unmatched_orders = result[result['_merge'] == 'left_only'].drop(columns='_merge')
print(unmatched_orders)
# order_id customer_id amount name
# 3 4 999 150 NaNการคงจำนวนแถวด้วย Left Join
เมื่อ DataFrame ฝั่งขวามีคีย์ที่ไม่ซ้ำกัน left join จะรับประกันว่าจะคงจำนวนแถวของตารางฝั่งซ้ายไว้ได้อย่างแม่นยำ อย่างไรก็ตาม หากตารางฝั่งขวามีค่าคีย์ซ้ำกัน left join จะทำให้จำนวนแถวเพิ่มขึ้นเช่นเดียวกับ inner join โปรดตรวจสอบเสมอว่าจำนวนแถวผลลัพธ์ตรงกับจำนวนแถวของตารางฝั่งซ้าย เมื่อคุณคาดหวังความสัมพันธ์แบบหนึ่งต่อหลาย
# Right table has duplicate keys -> row multiplication
orders_small = pd.DataFrame({'id': [1, 2], 'amount': [100, 200]})
multi_customer = pd.DataFrame({
'id': [1, 1], # duplicate!
'contact': ['Alice', 'Alice2']
})
result = pd.merge(orders_small, multi_customer, on='id', how='left')
print(len(result)) # 3 rows! order 1 appears twice
print(result)รูปแบบการใช้ Left Join ในโลกจริง
ตัวอย่างลำดับการทำงานที่ใช้ได้จริงมีดังนี้ เริ่มจากบันทึกธุรกรรม ทำ left join กับแค็ตตาล็อกสินค้าเพื่อดึงชื่อสินค้า จากนั้นทำ left join กับตารางลูกค้าเพื่อดึงชื่อลูกค้า เติมค่าเริ่มต้นให้กับข้อมูลที่ค้นหาไม่พบ การทำ left join ต่อเนื่องกันช่วยให้คงแถวธุรกรรมทุกแถวไว้ได้ แม้จะไม่มีระเบียนสินค้าหรือลูกค้าในตารางอ้างอิง
transactions = pd.DataFrame({
'txn_id': [1, 2, 3],
'cust_id': [10, 11, 99],
'prod_id': [20, 21, 20],
'total': [50, 30, 70]
})
custs = pd.DataFrame({'cust_id': [10, 11], 'cust_name': ['Alice', 'Bob']})
prods = pd.DataFrame({'prod_id': [20, 21], 'prod_name': ['Widget', 'Gadget']})
result = (
transactions
.merge(custs, on='cust_id', how='left')
.merge(prods, on='prod_id', how='left')
)
print(result)การตัดสินใจเลือกระหว่าง Left Join กับ Inner Join
การเลือกระหว่าง left และ inner join เป็นการตัดสินใจด้านตรรกะทางธุรกิจ กล่าวคือ ควรเก็บระเบียนที่ไม่พบรายการอ้างอิงไว้ หรือควรลบออกโดยไม่มีการแจ้งเตือน ให้ใช้ left join เมื่อการค้นหาข้อมูลอ้างอิงไม่พบเป็นสิ่งที่ยอมรับได้และคุณต้องการเก็บระเบียนหลักทั้งหมดไว้ ให้ใช้ inner join เมื่อการค้นหาข้อมูลอ้างอิงไม่พบหมายความว่าระเบียนนั้นไม่ถูกต้องและควรตัดออกจากการวิเคราะห์ โปรดบันทึกไว้เสมอว่าคุณเลือกวิธีใดและเพราะเหตุใด
# Left join: keep all transactions (some may have no product name)
result_left = pd.merge(transactions, prods, on='prod_id', how='left')
print('Left join rows:', len(result_left)) # same as transactions
# Inner join: only transactions with known product
result_inner = pd.merge(transactions, prods, on='prod_id', how='inner')
print('Inner join rows:', len(result_inner)) # may be fewerตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจของคุณเกี่ยวกับ left และ right join จากบทเรียนนี้
ทบทวนบทเรียน
ในบทเรียนนี้ คุณได้เรียนรู้ว่า left join จะคงทุกแถวจาก DataFrame ฝั่งซ้ายไว้ และเติม NaN ให้กับคอลัมน์ฝั่งขวาสำหรับแถวที่ไม่ตรงกัน right join เป็นภาพสะท้อนของวิธีดังกล่าว รูปแบบ anti-join ที่ใช้ indicator=True จะค้นหาแถวฝั่งซ้ายที่ไม่มีรายการตรงกันทางฝั่งขวา และการเลือกระหว่าง left กับ inner join เป็นการตัดสินใจด้านตรรกะทางธุรกิจ ต่อไปเราจะสำรวจการ join DataFrame ด้วยดัชนีแทนการใช้คอลัมน์
คำถามที่พบบ่อย
บทเรียน “การเชื่อมด้านซ้ายและด้านขวา” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การเชื่อมด้านซ้ายและด้านขวา” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Pandas & NumPy Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Pandas & NumPy Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การเชื่อมด้านซ้ายและด้านขวา”
ดำเนินการเชื่อมด้านซ้ายและด้านขวาเพื่อเก็บแถวทั้งหมดจากตารางหนึ่ง พร้อมจับคู่ระเบียนจากอีกตาราง คุณปฏิบัติ Pandas & NumPy Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Pandas & NumPy Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Pandas & NumPy Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “การเชื่อมด้านซ้ายและด้านขวา” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Pandas & NumPy Academy นี้ได้ไหม
ได้ บทเรียน Pandas & NumPy Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- pd.concat สำหรับการซ้อน DataFrames
- pd.merge: การเชื่อมแบบด้านในและด้านนอก
- การเชื่อมด้านซ้ายและด้านขวา
- การเชื่อมตามดัชนี