0Pricing
Pandas & NumPy Academy · درس

الربط حسب الفهرس

استخدم DataFrame.join() واضبط left_index/right_index=True في merge() لدمج DataFrame المتحاذية حسب فهرسها.

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

عمليات الربط المستندة إلى الفهرس

حتى الآن، دمجتم DataFrames من خلال مطابقة القيم في الأعمدة العادية. لكن المعلومات التي تريدون المطابقة بناءً عليها تكون أحيانًا مخزنة في فهرس DataFrame بدلًا من عمود. يدعم Pandas عمليات الربط المستندة إلى الفهرس من خلال DataFrame.join()، وكذلك من خلال pd.merge() باستخدام المعاملين left_index=True أو right_index=True.

الطريقة DataFrame.join()

DataFrame.join(other) طريقة مساعدة تنفّذ الربط باستخدام فهرس كلا DataFrame افتراضيًا. وهي مكافئة لاستدعاء pd.merge() باستخدام left_index=True, right_index=True. ويكون نوع الربط الافتراضي هو 'left'، على خلاف pd.merge() الذي يكون افتراضيه 'inner'. يجب أن يشترك كلا DataFrame في تسميات فهرس ذات معنى حتى ينتج الربط نتائج صحيحة.

import pandas as pd

profiles = pd.DataFrame(
    {'age': [25, 30, 22]},
    index=['alice', 'bob', 'carol']
)

scores = pd.DataFrame(
    {'score': [88, 95, 70]},
    index=['alice', 'carol', 'dave']
)

# join: left join on index (default)
result = profiles.join(scores)
print(result)
#        age  score
# alice   25   88.0
# bob     30    NaN   <- bob has no score
# carol   22   95.0

التحكم في نوع الربط باستخدام join()

مرّر المعامل how إلى join() للتحكم في الصفوف التي يتم الاحتفاظ بها، كما هو الحال مع pd.merge(). الخيارات هي 'left' (الافتراضي)، و'right'، و'inner'، و'outer'. على سبيل المثال، يحتفظ how='inner' بالفهارس الموجودة في كلا إطاري البيانات فقط، ويحذف صف alice إذا لم يكن له فهرس مطابق في الجدول الأيمن.

# Inner join on index: only rows present in BOTH indices
print(profiles.join(scores, how='inner'))
#        age  score
# alice   25     88
# carol   22     70

# Outer join: all indices from both
print(profiles.join(scores, how='outer'))
#        age  score
# alice  25.0   88.0
# bob    30.0    NaN
# carol  22.0   70.0
# dave    NaN   95.0

ضم عدة إطارات بيانات في آنٍ واحد

من أهم مزايا join() مقارنةً بـ pd.merge() أنه يقبل قائمة من إطارات البيانات، ويضمّها جميعًا إلى الإطار المستدعي باستدعاء واحد. يجب أن تكون جميع إطارات البيانات متوافقة في الفهارس. يكون ذلك ملائمًا جدًا عند وجود العديد من جداول الميزات المفهرسة بالمفتاح نفسه، مثل معرّف المستخدم أو التاريخ، والرغبة في تجميعها في إطار بيانات عريض واحد.

emails = pd.DataFrame({'email': ['a@x.com', 'b@x.com', 'c@x.com']},
                      index=['alice', 'bob', 'carol'])
city  = pd.DataFrame({'city': ['NY', 'LA', 'SF']},
                     index=['alice', 'bob', 'carol'])

# Join multiple DataFrames at once
result = profiles.join([emails, city])
print(result)
#        age    email city
# alice   25  a@x.com   NY
# bob     30  b@x.com   LA
# carol   22  c@x.com   SF

الضم باستخدام عمود في أحد الجدولين وفهرس في الآخر

يتيح pd.merge() الجمع بين المطابقة القائمة على الأعمدة والمطابقة القائمة على الفهارس باستخدام left_on/right_index أو left_index/right_on. يكون ذلك مفيدًا عندما يخزّن أحد إطاري البيانات المفتاح في عمود، بينما يستخدمه الآخر فهرسًا. لا يمكن تحقيق ذلك باستخدام join() وحده.

# orders has customer_id as a column; customers is indexed by customer_id
customers_indexed = pd.DataFrame(
    {'name': ['Alice', 'Bob', 'Carol']},
    index=[101, 102, 103]
)
orders = pd.DataFrame({
    'order_id': [1, 2, 3],
    'customer_id': [101, 102, 101]
})

result = pd.merge(orders, customers_indexed,
                  left_on='customer_id', right_index=True)
print(result)
#    order_id  customer_id   name
# 0         1          101  Alice
# 2         3          101  Alice
# 1         2          102    Bob

استخدام left_index و right_index في merge()

عندما يكون المفتاح فهرسًا في كلا إطاري البيانات، استخدم pd.merge(left, right, left_index=True, right_index=True). وهذا يكافئ join()، لكنه يستخدم نوع الضم الافتراضي 'inner' ومعاملات أكثر وضوحًا. كما تحصل على إمكانية استخدام جميع معاملات pd.merge() الأخرى، مثل suffixes وindicator.

# Both DataFrames indexed by user_id
demog = pd.DataFrame({'age': [25, 30]}, index=[1, 2])
behav = pd.DataFrame({'clicks': [10, 5]}, index=[1, 2])

# Equivalent joins
result1 = demog.join(behav)  # left join
result2 = pd.merge(demog, behav, left_index=True, right_index=True)  # inner join

print(result1)
print(result2)

لماذا نستخدم عمليات الضم القائمة على الفهرس؟

يُفضَّل استخدام عمليات الضم القائمة على الفهرس عندما تكون إطارات البيانات مرتبطة طبيعيًا بمعرّف ذي معنى، مثل معرّف المستخدم أو SKU المنتج أو التاريخ. يؤدي استخدام الفهرس في عمليات الضم إلى تجنّب إضافة أعمدة مفاتيح مكررة إلى إطار البيانات، وقد يكون أسرع لأن Pandas تحتفظ ببنى فهارس مرتبة تتيح البحث بزمن O(log n). وتشيع هذه العمليات خصوصًا في بيانات السلاسل الزمنية، حيث يكون DatetimeIndex هو مفتاح الضم الطبيعي.

# Time series example: join temperature and humidity by date index
import numpy as np
dates = pd.date_range('2024-01-01', periods=5)
temp = pd.DataFrame({'temp_c': [10, 12, 9, 11, 13]}, index=dates)
humid = pd.DataFrame({'humidity': [65, 70, 60, 75, 68]}, index=dates)

weather = temp.join(humid)
print(weather.head())

التعامل مع أسماء الأعمدة المتداخلة

عندما يحتوي كلا إطاري البيانات على أعمدة بالاسم نفسه (باستثناء المفتاح)، يرفع join() استثناء ValueError افتراضيًا ما لم توفّر المعاملين lsuffix وrsuffix. يعمل هذان المعاملان مثل suffixes في pd.merge()، إذ يُلحقان سلسلة نصية بأسماء الأعمدة المتداخلة في إطاري البيانات الأيسر والأيمن على التوالي.

df_a = pd.DataFrame({'value': [1, 2]}, index=['x', 'y'])
df_b = pd.DataFrame({'value': [10, 20]}, index=['x', 'y'])

# Without suffixes: raises ValueError
# result = df_a.join(df_b)

# With suffixes: disambiguate column names
result = df_a.join(df_b, lsuffix='_left', rsuffix='_right')
print(result)
#    value_left  value_right
# x           1           10
# y           2           20

set_index قبل الضم

من الأساليب الشائعة تعيين عمود ليصبح فهرسًا قبل إجراء عملية الضم، حتى تتمكن من استخدام صياغة join(). بعد الضم، يعيد reset_index() المفتاحَ كعمود عادي. يعبّر هذا النمط عن الخطوات بوضوح: ترقية المفتاح إلى فهرس، ثم إجراء الضم، ثم إعادة المفتاح إلى عمود، مما يوضّح المقصود لقرّاء الشيفرة لاحقًا.

orders_col = pd.DataFrame({'order_id': [1,2,3], 'customer_id': [10,20,10], 'amount': [100,200,150]})
cust_col = pd.DataFrame({'customer_id': [10,20], 'name': ['Alice','Bob']})

result = (
    orders_col.set_index('customer_id')
    .join(cust_col.set_index('customer_id'), how='left')
    .reset_index()
)
print(result)

محاذاة Series مع فهرس إطار بيانات

يمتلك Series فهرسًا أيضًا، ويمكنك إضافته كعمود جديد إلى إطار بيانات باستخدام الإسناد؛ إذ تحاذي Pandas قيم Series تلقائيًا مع تسميات الفهرس المطابقة. وهذه صورة خفيفة من الضم القائم على الفهرس، وتناسب الحالات التي تريد فيها إضافة عمود واحد من Series من دون استدعاء merge() أو join().

df = pd.DataFrame({'sales': [100, 200, 150]}, index=['A', 'B', 'C'])
tax_rate = pd.Series({'A': 0.1, 'B': 0.2, 'C': 0.15})

# Index alignment: Series aligns to DataFrame index automatically
df['tax'] = df['sales'] * tax_rate
print(df)
#    sales   tax
# A    100  10.0
# B    200  40.0
# C    150  22.5

أداء الضم باستخدام الفهرس

يكون الضم باستخدام فهرس مرتب أسرع من الضم باستخدام عمود عادي، لأن Pandas تستخدم البحث الثنائي على الفهرس المرتب. إذا كنت تجري عمليات ضم متكررة باستخدام المفتاح نفسه، فعيّن ذلك المفتاح فهرسًا مرة واحدة في بداية مسار المعالجة. وتكتسب هذه الخطوة أهمية خاصة في مسارات عمل السلاسل الزمنية، حيث تجري عمليات الضم باستخدام DatetimeIndex آلاف المرات عبر العديد من الملفات.

# Sort index before repeated joins for speed
left = left.sort_index()
right = right.sort_index()

# Both sorted -> Pandas uses merge path with binary search
result = left.join(right, how='inner')

# Check if index is sorted
print('Left sorted:', left.index.is_monotonic_increasing)
print('Right sorted:', right.index.is_monotonic_increasing)

تحقق سريع

اختبر مدى فهمك لعمليات الضم القائمة على الفهرس من هذا الدرس.

مراجعة الدرس

تعلّمت في هذا الدرس أن DataFrame.join() يجري الضم باستخدام الفهرس افتراضيًا مع ضم أيسر؛ وأن pd.merge() مع left_index=True/right_index=True يوفّر تحكمًا أكبر؛ وأنه يمكنك ضم عدة إطارات بيانات في آنٍ واحد بتمرير قائمة إلى join()؛ وأن استخدام فهرس مرتب يحسّن أداء الضم. بعد ذلك، سنستكشف إعادة تشكيل إطارات البيانات باستخدام pivot_table.

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

هل درس «الربط حسب الفهرس» مجاني؟

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

ماذا ستتعلم في «الربط حسب الفهرس»؟

استخدم DataFrame.join() واضبط left_index/right_index=True في merge() لدمج DataFrame المتحاذية حسب فهرسها. تتمرن على Pandas & NumPy Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

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

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

كم من الوقت يستغرق درس «الربط حسب الفهرس»؟

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

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

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

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

  1. ‏pd.concat لتكديس DataFrame
  2. ‏pd.merge: عمليات الربط الداخلي والخارجي
  3. عمليات الربط اليسرى واليمنى
  4. الربط حسب الفهرس
← العودة إلى Pandas & NumPy Academy