Pandas & NumPy Academy · บทเรียน

การแปลงและกรองด้วย GroupBy

ใช้ transform() เพื่อเพิ่มสถิติระดับกลุ่มกลับมาเป็นคอลัมน์ และใช้ filter() เพื่อเก็บเฉพาะกลุ่มที่ตรงตามเงื่อนไข

บทเรียน 4 จาก 413 ขั้นตอน

การแปลงและกรองด้วย GroupBy เป็นบทเรียน Pandas & NumPy Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Pandas & NumPy Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Pandas & NumPy Academy มีบทเรียนทั้งหมด 4 บทเรียน

ก้าวข้ามการรวมค่า

หลังจากเชี่ยวชาญ agg() แล้ว คำถามถัดไปที่เกิดขึ้นตามธรรมชาติคือ หากคุณต้องการเก็บแถวเดิมทั้งหมดไว้พร้อมเพิ่มสถิติระดับกลุ่มเข้าไป หรือเก็บไว้เฉพาะกลุ่มที่ตรงตามเงื่อนไข จะทำอย่างไร นี่คือจุดที่ transform() และ filter() เข้ามามีบทบาท เมธอดทั้งสองช่วยขยายการใช้งาน GroupBy จากการสรุปค่าอย่างง่าย ไปสู่การสร้างคุณลักษณะและการเลือกข้อมูล

ทำความเข้าใจ transform()

transform() ใช้ฟังก์ชันกับแต่ละกลุ่มและคืนผลลัพธ์ที่มีรูปร่างเหมือนกับ DataFrame เดิม — มีหนึ่งค่าต่อหนึ่งแถวเดิม ผลลัพธ์ของกลุ่มจะถูกกระจายกลับไปยังแต่ละแถวที่อยู่ในกลุ่มนั้น จึงเหมาะอย่างยิ่งสำหรับการเพิ่มสถิติระดับกลุ่มเป็นคอลัมน์ใหม่โดยไม่เปลี่ยนจำนวนแถว

import pandas as pd

df = pd.DataFrame({
    'dept':   ['Eng', 'HR', 'Eng', 'HR', 'Eng'],
    'salary': [90000, 60000, 95000, 62000, 88000]
})

# Add a column with each employee's department average salary
df['dept_avg'] = df.groupby('dept')['salary'].transform('mean')
print(df)
#    dept  salary    dept_avg
# 0   Eng   90000  91000.000
# 1    HR   60000  61000.000
# 2   Eng   95000  91000.000
# 3    HR   62000  61000.000
# 4   Eng   88000  91000.000

กรณีการใช้งาน transform() ที่พบบ่อย

การใช้งาน transform() ที่พบบ่อย ได้แก่ การเพิ่มค่าเฉลี่ยของกลุ่มเพื่อปรับค่าข้อมูลให้เป็นมาตรฐาน การเพิ่มผลรวมของกลุ่มเพื่อคำนวณสัดส่วนของแต่ละแถวเมื่อเทียบกับยอดรวม และการเพิ่มอันดับภายในกลุ่มเพื่อดูว่าสมาชิกแต่ละรายอยู่ในระดับใดเมื่อเทียบกับสมาชิกอื่นในกลุ่ม ทั้งหมดนี้จะคงรูปร่างและดัชนีเดิมไว้ ทำให้สามารถใช้ผลลัพธ์ร่วมกับคอลัมน์เดิมได้ทันที

# Percentage of each employee's salary within their department total
df['pct_of_dept'] = (
    df['salary'] / df.groupby('dept')['salary'].transform('sum') * 100
).round(1)
print(df[['dept', 'salary', 'pct_of_dept']])
# dept  salary  pct_of_dept
# Eng   90000        33.1
# HR    60000        49.2
# Eng   95000        34.9

การใช้ฟังก์ชันแบบกำหนดเองใน transform()

เช่นเดียวกับ agg() ตรงที่ transform() รับฟังก์ชันที่เรียกใช้งานได้ทุกชนิด นอกเหนือจากชื่อที่เป็นสตริง ฟังก์ชันจะได้รับ Series ของค่าสำหรับกลุ่มหนึ่งกลุ่ม และต้องคืน Series ที่มีความยาวเท่ากัน หรือคืนค่าเดี่ยว (ซึ่งจะถูกกระจายไปยังทุกแถว) การคืนค่าเดี่ยวเป็นกรณีการใช้งานที่พบบ่อยที่สุด หากคืน Series ที่มีความยาวต่างกัน จะเกิดข้อผิดพลาด

# Z-score normalisation within each department
def zscore(s):
    return (s - s.mean()) / s.std()

df['salary_zscore'] = df.groupby('dept')['salary'].transform(zscore)
print(df[['dept', 'salary', 'salary_zscore']].round(2))
# dept  salary  salary_zscore
# Eng   90000          -0.51
# HR    60000          -0.71
# Eng   95000           1.03

เปรียบเทียบ agg() กับ transform()

ความแตกต่างสำคัญคือ agg() ลดจำนวนแถวลง (เหลือหนึ่งแถวต่อกลุ่ม) ขณะที่ transform() คงจำนวนแถวไว้ (หนึ่งแถวต่อแถวเดิม) ใช้ agg() เพื่อสร้างตารางสรุป และใช้ transform() เพื่อเพิ่มข้อมูลระดับกลุ่มเป็นคอลัมน์คุณลักษณะใหม่ใน DataFrame เดิม

g = df.groupby('dept')['salary']

# agg: 2 rows (one per unique dept)
print(g.agg('mean'))
# dept
# Eng    91000.0
# HR     61000.0

# transform: 5 rows (one per original row)
print(g.transform('mean'))
# 0    91000.0
# 1    61000.0
# 2    91000.0
# 3    61000.0
# 4    91000.0

ทำความเข้าใจ filter()

filter() จะเก็บหรือละทิ้งทั้งกลุ่มโดยอิงจากฟังก์ชันบูลีน คุณส่งฟังก์ชันที่รับ DataFrame ย่อยของกลุ่มหนึ่งกลุ่ม และคืนค่า True (เก็บกลุ่มไว้) หรือ False (ลบกลุ่มออก) ผลลัพธ์คือส่วนย่อยของ DataFrame เดิม ซึ่งมีเฉพาะแถวจากกลุ่มที่ผ่านการทดสอบ

df2 = pd.DataFrame({
    'dept':   ['Eng', 'HR', 'Eng', 'HR', 'Eng', 'Legal'],
    'salary': [90000, 60000, 95000, 62000, 88000, 70000]
})

# Keep only departments with at least 2 employees
big_depts = df2.groupby('dept').filter(lambda g: len(g) >= 2)
print(big_depts)
# dept, salary rows: Eng(3) and HR(2) remain; Legal(1) dropped

กรองตามค่าการรวมของกลุ่ม

การใช้งาน filter() ที่พบบ่อยมากคือการเก็บกลุ่มที่ค่าการรวมผ่านเกณฑ์ที่กำหนด ตัวอย่างเช่น เก็บเฉพาะแผนกที่มีเงินเดือนเฉลี่ยสูงกว่าเป้าหมาย หรือเก็บเฉพาะหมวดหมู่สินค้าที่มียอดขายรวมสูงกว่าค่าขั้นต่ำ วิธีนี้ช่วยลบกลุ่มที่มีปริมาณน้อยออกก่อนการวิเคราะห์ขั้นต่อไป

# Keep only departments where average salary > 80000
high_paying = df2.groupby('dept').filter(
    lambda g: g['salary'].mean() > 80000
)
print(high_paying)
#    dept  salary
# 0   Eng   90000
# 2   Eng   95000
# 4   Eng   88000
# (HR avg is 61000, filtered out)

การใช้ transform() และ filter() ร่วมกัน

คุณสามารถใช้ transform() และ filter() ตามลำดับ เพื่อเพิ่มข้อมูลให้สมบูรณ์แล้วจึงจำกัดข้อมูลให้แคบลง ขั้นแรกใช้ filter() เพื่อลบกลุ่มที่ไม่เกี่ยวข้อง จากนั้นใช้ transform() กับผลลัพธ์ที่กรองแล้วเพื่อเพิ่มคุณลักษณะระดับกลุ่ม การผสมผสานนี้ทำให้ได้ชุดข้อมูลย่อยที่สะอาดและมีคุณลักษณะครบถ้วน พร้อมสำหรับการสร้างแบบจำลองหรือการจัดทำรายงาน

# Step 1: keep only large departments
filtered = df2.groupby('dept').filter(lambda g: len(g) >= 2)

# Step 2: add group mean salary to the filtered result
filtered = filtered.copy()
filtered['dept_avg'] = filtered.groupby('dept')['salary'].transform('mean')
print(filtered)

ใช้ transform() เติมค่าล่วงหน้าภายในกลุ่ม

transform() ยังมีประโยชน์กับฟังก์ชันที่ไม่ใช่ตัวเลขด้วย รูปแบบที่นิยมคือการเติมค่าที่หายไปภายในกลุ่ม โดยใช้การเติมค่าล่วงหน้าหรือค่ามัธยฐานของกลุ่ม ซึ่งดีกว่าการเติมค่าทั้งหมดด้วยค่าเดียวเป็นอย่างมาก ส่งฟังก์ชันแลมบ์ดาที่เรียก fillna() กับ Series ของกลุ่ม แล้วผลลัพธ์จะมีดัชนีเดียวกับ DataFrame เดิม

import numpy as np

df3 = pd.DataFrame({
    'dept':   ['Eng', 'Eng', 'HR', 'HR', 'Eng'],
    'salary': [90000, np.nan, 60000, np.nan, 88000]
})

# Fill NaN with the group mean
df3['salary_filled'] = df3.groupby('dept')['salary'].transform(
    lambda s: s.fillna(s.mean())
)
print(df3)

รูปแบบเชิงปฏิบัติ: ตำแหน่งสัมพัทธ์

กรณีการใช้งานทางธุรกิจที่มีประโยชน์อย่างหนึ่งคือการคำนวณตำแหน่งของแต่ละแถวเมื่อเทียบกับกลุ่มของตนเอง ด้วยการใช้ transform() ร่วมกับการคำนวณทางคณิตศาสตร์ คุณสามารถเพิ่มคอลัมน์ เช่น เงินเดือนลบด้วยค่าเฉลี่ยของกลุ่ม (ค่าความเบี่ยงเบน) เงินเดือนในรูปเศษส่วนของยอดรวมกลุ่ม หรือค่าสถานะบูลีนที่ระบุว่าพนักงานรายนี้มีรายได้สูงกว่าค่ามัธยฐานของกลุ่มหรือไม่ คุณลักษณะเหล่านี้มีประโยชน์อย่างมากสำหรับแดชบอร์ดและแบบจำลองการเรียนรู้ของเครื่อง

df['dept_total'] = df.groupby('dept')['salary'].transform('sum')
df['pct_of_total'] = (df['salary'] / df['dept_total'] * 100).round(1)
df['above_avg'] = df['salary'] > df.groupby('dept')['salary'].transform('mean')
print(df[['dept', 'salary', 'pct_of_total', 'above_avg']])

ข้อควรพิจารณาด้านประสิทธิภาพ

ทั้ง transform() และ filter() ที่ใช้ฟังก์ชันในตัวแบบสตริงทำงานได้รวดเร็ว เพราะใช้เส้นทางการทำงานของโค้ดที่ได้รับการปรับให้เหมาะสม อย่างไรก็ตาม เมื่อคุณส่งฟังก์ชันแลมบ์ดาหรือฟังก์ชัน Python แบบกำหนดเอง Pandas ต้องเรียกฟังก์ชันนั้นหนึ่งครั้งต่อหนึ่งกลุ่ม ซึ่งอาจช้าเมื่อข้อมูลมีกลุ่มจำนวนมาก หากต้องการประสิทธิภาพสูงสุดกับชุดข้อมูลขนาดใหญ่ ให้ตรวจสอบว่าตรรกะแบบกำหนดเองของคุณสามารถเขียนด้วยฟังก์ชันในตัวแบบสตริงแทนได้หรือไม่

# Slower: custom lambda (called once per group)
df['dept_mean_slow'] = df.groupby('dept')['salary'].transform(lambda s: s.mean())

# Faster: built-in string shortcut (vectorised C path)
df['dept_mean_fast'] = df.groupby('dept')['salary'].transform('mean')

# Both give identical results, but the built-in is significantly faster

ตรวจสอบความเข้าใจ

ทดสอบความเข้าใจเกี่ยวกับ GroupBy transform() และ filter() จากบทเรียนนี้

สรุปบทเรียน

ในบทเรียนนี้ คุณได้เรียนรู้ว่า transform() คืนค่าสถิติของกลุ่มที่ถูกกระจายกลับไปจนมีจำนวนแถวเท่ากับแถวเดิม จึงเหมาะสำหรับการเพิ่มคุณลักษณะระดับกลุ่ม filter() เก็บหรือลบทั้งกลุ่มโดยอิงตามเงื่อนไขบูลีน และการใช้ทั้งสองเมธอดร่วมกันช่วยให้คุณสร้างชุดข้อมูลที่มีคุณลักษณะครบถ้วนและผ่านการกรองแล้วสำหรับการวิเคราะห์ในขั้นต่อไป บทถัดไปเราจะสำรวจวิธีรวม DataFrame ด้วย pd.concat

เริ่มต้นได้ฟรี

เรียนรู้ Python ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
30
บทเรียน
120

คำถามที่พบบ่อย

บทเรียน “การแปลงและกรองด้วย GroupBy” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การแปลงและกรองด้วย GroupBy” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Pandas & NumPy Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Pandas & NumPy Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การแปลงและกรองด้วย GroupBy”

ใช้ transform() เพื่อเพิ่มสถิติระดับกลุ่มกลับมาเป็นคอลัมน์ และใช้ filter() เพื่อเก็บเฉพาะกลุ่มที่ตรงตามเงื่อนไข คุณปฏิบัติ Pandas & NumPy Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Pandas & NumPy Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Pandas & NumPy Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การแปลงและกรองด้วย GroupBy” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Pandas & NumPy Academy นี้ได้ไหม

ได้ บทเรียน Pandas & NumPy Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. รูปแบบแยก-ประมวลผล-รวม
  2. GroupBy ด้วยคีย์เดียวและหลายคีย์
  3. เมธอด agg()
  4. การแปลงและกรองด้วย GroupBy
← กลับไปที่ Pandas & NumPy Academy