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

อันดับและเปอร์เซ็นไทล์ภายในกลุ่ม

คำนวณอันดับภายในกลุ่มด้วย groupby().rank() และสร้างช่วงเปอร์เซ็นไทล์ด้วย pd.qcut เพื่อการเปรียบเทียบเชิงสัมพัทธ์

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

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

เหตุใดจึงต้องจัดอันดับภายในกลุ่ม

ค่าดิบมักมีความหมายน้อยกว่าอันดับสัมพัทธ์ ตัวแทนฝ่ายขายที่สร้างรายได้ต่อเดือน 50,000 ดอลลาร์ถือว่ามีผลงานยอดเยี่ยมหากค่าเฉลี่ยอยู่ที่ 30,000 ดอลลาร์ แต่ถือว่ามีผลงานต่ำกว่าค่าเฉลี่ยหากค่าเฉลี่ยอยู่ที่ 80,000 ดอลลาร์ การคำนวณอันดับภายในกลุ่ม (เช่น จัดอันดับภายในแต่ละภูมิภาคหรือแต่ละไตรมาส) ช่วยให้ได้การเปรียบเทียบที่ปรับให้อยู่ในมาตรฐานเดียวกัน โดยคำนึงถึงค่าฐานที่แตกต่างกันระหว่างกลุ่ม Pandas ทำให้การจัดอันดับภายในกลุ่มทำได้ง่ายด้วย groupby().rank()

import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'rep': ['Alice', 'Bob', 'Carol', 'Dave', 'Eve',
            'Frank', 'Grace', 'Hank', 'Iris', 'Jake'],
    'region': ['East']*5 + ['West']*5,
    'sales': np.random.randint(30000, 100000, 10)
})
print(df.sort_values('region'))

Series.rank() — การจัดอันดับพื้นฐาน

Series.rank() กำหนดอันดับให้แต่ละค่า โดยอันดับ 1 คือค่าที่น้อยที่สุด และอันดับ n คือค่าที่มากที่สุด พารามิเตอร์ ascending=False จะกลับทิศทาง ทำให้อันดับ 1 เป็นค่าที่มากที่สุด ผลลัพธ์จะเป็น Series แบบทศนิยม (ไม่ใช่จำนวนเต็ม) เพราะโดยค่าเริ่มต้นค่าที่เท่ากันจะได้รับอันดับเฉลี่ย หากคอลัมน์มี 5 ค่า อันดับจะอยู่ในช่วง 1.0 ถึง 5.0 หรือในกรณีที่มีค่าเท่ากัน บางค่าอาจใช้อันดับร่วมกัน เช่น 2.5

import pandas as pd

s = pd.Series([80, 45, 90, 45, 70])

print('Values:', s.values)
print('Rank (ascending=True, default):', s.rank().values)
print('Rank (ascending=False — best=1):', s.rank(ascending=False).values)
# Note: two 45s share ranks 1 and 2 → both get 1.5

วิธีจัดการค่าที่เท่ากันใน rank()

พารามิเตอร์ method ควบคุมการจัดการค่าที่เท่ากัน ตัวเลือกมีดังนี้ 'average' (ค่าเริ่มต้น — ค่าที่เท่ากันใช้อันดับเฉลี่ยร่วมกัน), 'min' (ค่าที่เท่ากันทั้งหมดได้รับอันดับต่ำสุด), 'max' (ทั้งหมดได้รับอันดับสูงสุด), 'first' (จัดอันดับตามลำดับที่ปรากฏ — ไม่มีอันดับที่เท่ากัน) และ 'dense' (อันดับไม่มีช่องว่าง — 1, 2, 3, 3, 4 จะกลายเป็น 1, 2, 3, 3, 4 แทนที่จะเป็น 1, 2, 3, 3, 5) วิธี 'dense' เหมาะที่สุดสำหรับการจัดอันดับในลักษณะเปอร์เซ็นไทล์

import pandas as pd

s = pd.Series([80, 45, 90, 45, 70])

result = pd.DataFrame({
    'value': s,
    'average': s.rank(method='average'),
    'min': s.rank(method='min'),
    'max': s.rank(method='max'),
    'first': s.rank(method='first'),
    'dense': s.rank(method='dense')
})
print(result)

การจัดอันดับภายในกลุ่มด้วย groupby().rank()

groupby('group_col')['value_col'].rank() คำนวณอันดับแยกกันภายในแต่ละกลุ่ม อันดับจะเริ่มต้นใหม่เมื่อเริ่มกลุ่มแต่ละกลุ่ม ดังนั้นผู้ที่มีผลงานดีที่สุดในภูมิภาคตะวันออกจะได้อันดับ 1 ในกลุ่มตะวันออก และผู้ที่มีผลงานดีที่สุดในภูมิภาคตะวันตกก็จะได้อันดับ 1 ในกลุ่มตะวันตกเช่นกัน นี่คือเหตุผลที่ groupby rank มีประโยชน์อย่างมากสำหรับการเปรียบเทียบระหว่างกลุ่มอย่างเป็นธรรม

import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'rep': list('ABCDEABCDE'),
    'region': ['East']*5 + ['West']*5,
    'sales': np.random.randint(30000, 100000, 10)
})

# Rank within each region (best = rank 1)
df['rank_in_region'] = df.groupby('region')['sales'].rank(ascending=False, method='min')
df_sorted = df.sort_values(['region', 'rank_in_region'])
print(df_sorted.to_string(index=False))

การจัดอันดับเปอร์เซ็นไทล์ด้วย rank(pct=True)

การกำหนด pct=True ใน rank() จะส่งคืนอันดับเปอร์เซ็นไทล์ ซึ่งเป็นค่าระหว่าง 0 ถึง 1 ที่แสดงสัดส่วนของค่าในกลุ่มที่น้อยกว่าหรือเท่ากับค่าปัจจุบัน อันดับเปอร์เซ็นไทล์ 0.8 หมายความว่าค่านั้นอยู่ที่เปอร์เซ็นไทล์ที่ 80 ซึ่งสูงกว่าค่าทั้งหมด 80% การปรับมาตรฐานนี้ทำให้สามารถเปรียบเทียบค่าจากกลุ่มที่มีขนาดแตกต่างกันได้โดยตรง โดยไม่จำเป็นต้องทราบขนาดจริงของแต่ละกลุ่ม

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({
    'name': list('ABCDEFGHIJ'),
    'region': ['East']*5 + ['West']*5,
    'score': np.random.randint(50, 100, 10)
})

# Percentile rank within region
df['pct_rank'] = df.groupby('region')['score'].rank(pct=True)
df['percentile'] = (df['pct_rank'] * 100).round(0).astype(int)
print(df.sort_values(['region', 'percentile'], ascending=[True, False]).to_string(index=False))

pd.qcut: การแบ่งช่วงตามควอนไทล์

pd.qcut(series, q) แบ่งค่าออกเป็นช่วงที่มีความถี่เท่ากันจำนวน q ช่วง เพื่อให้แต่ละช่วงมีจำนวนค่าที่สังเกตได้ใกล้เคียงกัน ต่างจาก pd.cut ที่ใช้ช่วงความกว้างเท่ากัน pd.qcut จะปรับขอบเขตของช่วงให้สอดคล้องกับการกระจายของข้อมูล วิธีนี้เหมาะอย่างยิ่งสำหรับการสร้างควอร์ไทล์ (q=4) ควินไทล์ (q=5) หรือเดไซล์ (q=10) เพื่อแบ่งระดับผลงาน

import pandas as pd
import numpy as np

np.random.seed(42)
sales = pd.Series(np.random.exponential(scale=50000, size=100))

# Divide into quartiles
quartiles = pd.qcut(sales, q=4, labels=['Q1', 'Q2', 'Q3', 'Q4'])

result = pd.DataFrame({'sales': sales, 'quartile': quartiles})
print('Quartile counts (should be ~25 each):')
print(result['quartile'].value_counts().sort_index())
print('\nMean sales per quartile:')
print(result.groupby('quartile')['sales'].mean().round(0))

pd.cut เทียบกับ pd.qcut

pd.cut(series, bins=n) สร้างช่วงที่มีความกว้างเท่ากัน (ช่วงเท่ากันแต่จำนวนค่าแตกต่างกัน) ส่วน pd.qcut(series, q=n) สร้างช่วงที่มีความถี่เท่ากัน (จำนวนค่าเท่ากันแต่ช่วงแตกต่างกัน) สำหรับข้อมูลที่เบ้ pd.cut จะทำให้ช่วงบริเวณปลายการกระจายแทบไม่มีข้อมูล ขณะที่ pd.qcut จะกระจายค่าที่สังเกตได้อย่างสม่ำเสมอ เลือกใช้ pd.cut เมื่อขอบเขตช่วงมีความหมายทางธุรกิจตามธรรมชาติ (เช่น ช่วงราคา กลุ่มอายุ) และเลือกใช้ pd.qcut สำหรับการแบ่งระดับผลงานที่ต้องการให้แต่ละกลุ่มมีขนาดเท่ากัน

import pandas as pd
import numpy as np

np.random.seed(0)
# Right-skewed data
data = pd.Series(np.random.exponential(1, 100))

cut_result = pd.cut(data, bins=5).value_counts().sort_index()
qcut_result = pd.qcut(data, q=5).value_counts().sort_index()

print('Equal-width bins (pd.cut) — uneven counts:')
print(cut_result.to_string())
print('\nEqual-frequency bins (pd.qcut) — even counts:')
print(qcut_result.to_string())

การสร้างป้ายกำกับเดไซล์ด้วย pd.qcut

pd.qcut(series, q=10, labels=range(1,11)) กำหนดให้ค่าที่สังเกตได้แต่ละค่าอยู่ในเดไซล์ของตน (1 ถึง 10) นี่เป็นเทคนิคมาตรฐานในการวิเคราะห์การตลาด (เดไซล์มูลค่าลูกค้า) การให้คะแนนสินเชื่อ (เดไซล์ความเสี่ยง) และการทดสอบ AB (เดไซล์ปริมาณการเข้าชมสำหรับการวิเคราะห์กลุ่มตามรุ่น) พารามิเตอร์ labels รับรายการใดก็ได้ที่มีความยาวเท่ากับ q — ใช้ข้อความอย่าง ['Bottom 10%', ..., 'Top 10%'] เพื่อให้ผลลัพธ์อ่านเข้าใจได้ง่ายขึ้น

import pandas as pd
import numpy as np

np.random.seed(7)
customer_value = pd.Series(np.random.exponential(500, 1000))

# Assign to deciles 1-10
decile_labels = [f'D{i}' for i in range(1, 11)]
customer_decile = pd.qcut(
    customer_value,
    q=10,
    labels=decile_labels
)

result = pd.DataFrame({'value': customer_value, 'decile': customer_decile})
print('Mean customer value per decile:')
print(result.groupby('decile')['value'].mean().round(0))

ช่วงเปอร์เซ็นไทล์ภายในกลุ่ม

ผสาน groupby กับ pd.qcut โดยใช้ transform เพื่อสร้างช่วงเปอร์เซ็นไทล์ภายในแต่ละกลุ่ม วิธีนี้มีประโยชน์เมื่อต้องการจัดอันดับลูกค้าภายในแต่ละภูมิภาค (แทนการจัดอันดับทั่วทั้งข้อมูล) เพราะลูกค้าที่อยู่ในเดไซล์ล่างสุดเมื่อดูทั้งข้อมูล อาจอยู่ในเดไซล์บนสุดของภูมิภาคตนเอง ใช้ groupby('group')['value'].transform(lambda x: pd.qcut(x, q=4, labels=['Q1','Q2','Q3','Q4']))

import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    'customer': range(20),
    'region': ['North']*10 + ['South']*10,
    'spend': np.random.randint(100, 1000, 20)
})

# Quartile within each region
def quartile_label(x):
    return pd.qcut(x, q=4, labels=['Q1','Q2','Q3','Q4'])

df['region_quartile'] = df.groupby('region')['spend'].transform(quartile_label)
print(df.sort_values(['region', 'region_quartile']).to_string(index=False))

N อันดับแรกภายในกลุ่ม

คำถามทางธุรกิจที่พบบ่อยคือ “ใครคือผู้มีผลงานดีที่สุด 3 อันดับแรกในแต่ละภูมิภาค” ให้ใช้ groupby().rank() แล้วกรองตามอันดับด้วย df[df['rank_col'] <= 3] วิธีนี้ทำงานได้อย่างเรียบร้อยกับกลุ่มทุกขนาด และจัดการค่าที่เท่ากันได้อย่างเหมาะสม โดยอาจคงไว้มากกว่า 3 แถวหากมีอันดับเท่ากันที่จุดตัด อีกทางเลือกหนึ่งคือใช้ groupby().nlargest(n) ซึ่งส่งคืนค่าที่มากที่สุด n ค่าในแต่ละกลุ่มโดยตรง โดยไม่ต้องเพิ่มคอลัมน์อันดับ

import pandas as pd
import numpy as np

np.random.seed(0)
df = pd.DataFrame({
    'rep': [f'Rep_{i}' for i in range(15)],
    'region': ['East']*5 + ['West']*5 + ['North']*5,
    'revenue': np.random.randint(40000, 120000, 15)
})

df['region_rank'] = df.groupby('region')['revenue'].rank(ascending=False, method='min')

print('Top 2 per region:')
top2 = df[df['region_rank'] <= 2].sort_values(['region', 'region_rank'])
print(top2[['rep', 'region', 'revenue', 'region_rank']].to_string(index=False))

การผสาน Rank และ Transform เพื่อการปรับมาตรฐาน

คุณสามารถใช้ groupby().rank(pct=True) ร่วมกับ transform เพื่อเพิ่มคอลัมน์อันดับเปอร์เซ็นไทล์ลงใน DataFrame เดิมได้ คอลัมน์ที่ปรับมาตรฐานนี้มักมีประโยชน์ในฐานะคุณลักษณะของแบบจำลองมากกว่าค่าดิบ เพราะไม่ขึ้นกับสเกลและสามารถเปรียบเทียบระหว่างกลุ่มได้ สำหรับการเรียนรู้ของเครื่อง อันดับเปอร์เซ็นไทล์เป็นทางเลือกง่าย ๆ แทนการทำให้เป็นมาตรฐาน (การคำนวณคะแนน z) และทนต่อค่าผิดปกติได้ดีกว่า

import pandas as pd
import numpy as np

np.random.seed(1)
df = pd.DataFrame({
    'product': np.random.choice(['A', 'B', 'C'], 30),
    'score': np.random.randint(50, 100, 30)
})

# Percentile rank within each product group
df['global_pct'] = df['score'].rank(pct=True).round(3)
df['group_pct'] = df.groupby('product')['score'].rank(pct=True).round(3)

print(df.sort_values(['product', 'score']).head(12).to_string(index=False))

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจเกี่ยวกับการดำเนินการด้านอันดับและเปอร์เซ็นไทล์จากบทเรียนนี้

สรุปบทเรียน

ในบทเรียนนี้ คุณได้เรียนรู้ว่า Series.rank() คำนวณอันดับตัวเลขพร้อมกำหนดวิธีจัดการค่าที่เท่ากันได้ groupby().rank() เริ่มอันดับใหม่ภายในแต่ละกลุ่มเพื่อให้เปรียบเทียบระหว่างกลุ่มได้อย่างเป็นธรรม pct=True แปลงอันดับเป็นเปอร์เซ็นไทล์ (0 ถึง 1) และ pd.qcut สร้างช่วงที่มีความถี่เท่ากันสำหรับการกำหนดระดับควอร์ไทล์ เดไซล์ และเปอร์เซ็นไทล์ ต่อไป เราจะสำรวจเคล็ดลับด้านประสิทธิภาพของ Pandas — การทำโปรไฟล์ การหลีกเลี่ยงลูปที่ช้า และชนิดข้อมูลที่มีประสิทธิภาพ

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

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

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

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

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

บทเรียน “อันดับและเปอร์เซ็นไทล์ภายในกลุ่ม” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “อันดับและเปอร์เซ็นไทล์ภายในกลุ่ม”

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

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

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

บทเรียน “อันดับและเปอร์เซ็นไทล์ภายในกลุ่ม” ใช้เวลานานแค่ไหน

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

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

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

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

  1. หน้าต่างเลื่อน
  2. หน้าต่างสะสม
  3. ค่าเฉลี่ยเคลื่อนที่แบบถ่วงน้ำหนักเอ็กซ์โพเนนเชียล
  4. อันดับและเปอร์เซ็นไทล์ภายในกลุ่ม
← กลับไปที่ Pandas & NumPy Academy