Pandas & NumPy Academy · درس

الرتب والمئينات داخل المجموعات

احسب الرتب داخل المجموعة باستخدام groupby().rank()، وأنشئ فئات مئينية باستخدام pd.qcut للمقارنات النسبية.

الدرس 4 من 413 خطوة

الرتب والمئينات داخل المجموعات درس مجاني في Pandas & NumPy Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 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 من نوع float وليست integer، لأن القيم المتساوية تُحل افتراضيًا بحساب متوسط رتبها. بالنسبة إلى عمود يحوي 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 مفيدًا جدًا للمقارنات العادلة بين المجموعات.

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). وهذه تقنية شائعة في تحليلات التسويق (أعشار قيمة العملاء)، وتقييم الجدارة الائتمانية (أعشار المخاطر)، واختبارات A/B (أعشار الزيارات لتحليل المجموعات). ويمكن أن تكون المعلمة 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))

دمج الرتبة وTransform للتطبيع

يمكنك استخدام groupby().rank(pct=True) مع transform لإضافة عمود للرتبة المئينية إلى DataFrame الأصلي. وغالبًا ما يكون هذا العمود المُطبَّع أكثر فائدة كميزة للنموذج من القيمة الخام، لأنه مستقل عن المقياس وقابل للمقارنة بين المجموعات. وفي تعلّم الآلة، تُعد الرتب المئينية بديلًا بسيطًا عن التوحيد القياسي (حساب z-score)، كما أنها أكثر مقاومة للقيم الشاذة.

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 مع معلم ذكاء اصطناعي — مجانًا

اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.

الدورات
30
الدروس
120

الأسئلة الشائعة

هل درس «الرتب والمئينات داخل المجموعات» مجاني؟

نعم — نص درس «الرتب والمئينات داخل المجموعات» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Pandas & NumPy Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Pandas & NumPy Academy 4 دروس في المجموع.

ماذا ستتعلم في «الرتب والمئينات داخل المجموعات»؟

احسب الرتب داخل المجموعة باستخدام groupby().rank()، وأنشئ فئات مئينية باستخدام pd.qcut للمقارنات النسبية. تتمرن على Pandas & NumPy Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Pandas & NumPy Academy؟

لا تُشترط خبرة سابقة. Pandas & NumPy Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «الرتب والمئينات داخل المجموعات»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Pandas & NumPy Academy هذا؟

نعم. كل درس في Pandas & NumPy Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. النوافذ المتحركة
  2. النوافذ التوسعية
  3. المتوسط المتحرك الموزون أسيًا
  4. الرتب والمئينات داخل المجموعات
← العودة إلى Pandas & NumPy Academy