EduFlow
Python لتحليل البيانات
⁦0%⁩

الوحدة 2 · أساسيات pandas

تصفية الصفوف وترتيبها

18 دقراءة 4 دتمرين Python

الدرس في لمحة

صفِّ الصفوف بالأقنعة المنطقية، وادمج الشروط بـ & و | و ~، واستخدم isin و between للتصفيات الشائعة، ورتّب الصفوف أو اختر أعلاها بـ sort_values و nlargest.

  1. 1الأقنعة المنطقية
  2. 2دمج الشروط
  3. 3طريقان مختصران: isin و between
  4. 4الترتيب واختيار الأعلى

لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.

سؤال رئيس النمو له نافذة زمنية: الربع الرابع من 2025. قبل أن تستطيع تفسير ذلك الربع، تحتاج إلى عزله، ثم تقطيعه أكثر: أيّ هذه الطلبات استخدم كوبونًا، وأيّها جاء عبر الـ marketplace، وأيّها كان من طلبات الجمعة السوداء. كل واحد من هذه الأسئلة تصفية، وتصفّي pandas بالطريقة نفسها في كل مرة: ابنِ عمودًا من True/False، ثم احتفظ بصفوف True.

الأقنعة المنطقية

المقارنة على عمود لا تعيد إجابة واحدة؛ بل تعيد إجابة لكل صف:

Python
import pandas as pd

orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
is_free = orders["shipping_fee"] == 0
print(is_free.head())
print(is_free.sum(), "orders with free shipping")
print(round(is_free.mean(), 3), "share of all orders")

تُسمّى تلك الـ Series المنطقية قناعًا (mask). جمعه يعدّ قيم True، ومتوسطه هو حصة الصفوف المطابقة: 43% من طلبات Cartwheel شُحنت مجانًا. كثيرًا ما تعرف ما تحتاجه من العدد وحده، دون تصفية أي شيء.

لتحتفظ بالصفوف المطابقة، ضع القناع داخل الأقواس المربعة، أو داخل .loc حين تريد أيضًا اختيار الأعمدة:

Python
import pandas as pd

orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
cancelled = orders[orders["status"] == "cancelled"]
print(len(cancelled))
print(orders.loc[orders["shipping_fee"] == 0, ["order_id", "channel", "coupon_code"]].head())

دمج الشروط

الأسئلة الحقيقية فيها عدة شروط. تستخدم pandas العلامة & بمعنى “و”، و| بمعنى “أو”، و~ بمعنى “ليس”، وتطبّقها صفًا بصف:

Python
import pandas as pd

orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
in_q4 = (orders["order_date"] >= "2025-10-01") & (orders["order_date"] < "2026-01-01")
not_cancelled = orders["status"] != "cancelled"
q4 = orders[in_q4 & not_cancelled]
print(len(orders[in_q4]), "orders in Q4 2025,", len(q4), "not cancelled")
print(q4["channel"].value_counts())

منح كل قناع اسمًا، كما هنا، يُبقي التصفيات الطويلة مقروءة، ويتيح لك طباعة كل شرط وعدّه منفردًا حين تبدو نتيجة خاطئة. ويمكن مقارنة عمود datetime بتاريخ مكتوب كنص، "2025-10-01"، فتحوّله pandas نيابةً عنك. والحد الأعلى هو “قبل 1 يناير”، لا “في 31 ديسمبر أو قبله”، لأن طلبات 31 ديسمبر لها وقت بعد منتصف الليل.

طريقان مختصران: isin و between

مطابقة أيٍّ من عدة قيم بسلاسل من | تصبح طويلة. أما isin فتأخذ قائمة:

Python
import pandas as pd

orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
problem = orders["status"].isin(["cancelled", "returned"])
print(problem.sum(), "cancelled or returned")

black_friday_week = orders["order_date"].between("2025-11-24", "2025-11-30 23:59:59")
print(black_friday_week.sum(), "orders in Black Friday week 2025")

bf = orders[orders["coupon_code"] == "BLACKFRIDAY25"]
print(bf["order_date"].dt.month.value_counts().head(3))

تشمل between الطرفين، ولهذا يحمل الحد الأعلى وقتًا. والأسطر الأخيرة تحتوي اكتشافًا حقيقيًا: من بين 124 طلبًا استُخدم فيها الكوبون BLACKFRIDAY25، يقع 91 في نوفمبر، والبقية متفرّقة على مدار السنة. هل تُرك الكود فعّالًا، أم نُشر على موقع كوبونات، أم أن البيانات خاطئة؟ التصفيات لا تجيب عن ذلك، لكنها تُظهر السؤال، والمحللون الجيدون يحملونه إلى من يديرون العرض الترويجي قبل البناء عليه. (تستخرج .dt.month رقم الشهر؛ ويشرح الدرس 4.4 الـ accessor المسمّى dt بالتفصيل.)

الجدول المُصفّى جدول جديد

تعيد التصفية DataFrame جديدًا. الجدول q4 في المثال السابق لا يتذكّر أنه جاء من orders، ويجب أن تعامله كجدول مستقل: إذا أردت لاحقًا إضافة عمود إليه، فتضيفه إلى q4، ويبقى orders كما هو. وفي كود pandas 2 سترى كثيرًا .copy() بعد التصفية: فهي توضّح ذلك وتُسكت تحذير SettingWithCopyWarning الذي تطبعه pandas 2 حين تضيف عمودًا إلى جدول مُصفّى. أما مع Copy-on-Write، وهو السلوك الافتراضي منذ pandas 3.0 ويمكنك تفعيله في pandas 2 بـ pd.options.mode.copy_on_write = True، فكل نتيجة مُصفّاة تتصرّف أصلًا كنسخة مستقلة. ويبيّن الدرس 2.5 لماذا يهم هذا حين تبدأ بتغيير القيم.

الترتيب واختيار الأعلى

ترتّب sort_values الصفوف بحسب عمود واحد أو أكثر:

Python
import pandas as pd

orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
latest = orders.sort_values("order_date", ascending=False)
print(latest[["order_id", "order_date", "status"]].head(3))

by_fee = orders.sort_values(["shipping_fee", "order_date"], ascending=[False, False])
print(by_fee[["order_id", "shipping_fee", "order_date"]].head(3))
print(orders.nlargest(3, "shipping_fee")[["order_id", "shipping_fee"]])

مع قائمة أعمدة، يكسر العمود الثاني التعادل في الأول، وتأخذ ascending قائمة مطابقة. وnlargest(n, column) وnsmallest طريقان مختصران لـ “رتّب وخذ أعلى n”؛ وهما أسرع على الجداول الكبيرة ويعبّران عمّا تقصده.

آخر ثلاثة طلبات ما زالت processing أو shipped: قُدّمت في آخر أيام ديسمبر ولم تكن قد سُلّمت حين صُدّرت البيانات. هذا قرار آخر في تعريفك للإيراد، وستتخذه في القسم 4.

في التمرين تعزل الربع الرابع من 2025 وتقيس استخدام الكوبونات فيه. وفي الدرس التالي تضيف أعمدة جديدة، مثل إيراد كل بند، وتتعلّم الطريقة الصحيحة الوحيدة لتغيير القيم في DataFrame.

أهم النقاط

  • المقارنة على عمود تعيد قناعًا منطقيًا (boolean mask)؛ وdf[mask] أو df.loc[mask, cols] تحتفظ بالصفوف التي يكون فيها True.
  • ادمج الأقنعة بـ & (و) و| (أو) و~ (ليس)، وضع كل شرط بين قوسين.
  • mask.sum() تعدّ الصفوف المطابقة وmask.mean() تعطي حصتها، دون تصفية أي شيء.
  • الدالة isin([...]) تحلّ محل السلاسل الطويلة من == مع |، وbetween(a, b) تشمل الطرفين.
  • تقبل sort_values قوائم للترتيب بعدة أعمدة؛ وnlargest(n, col) هي الطريق المختصر لقائمة الأعلى n.

قراءات إضافية

تحقّق من فهمك

3 أسئلة

السؤال 1 من 3

أيّ سطر يحتفظ بطلبات الويب التي استخدمت كوبونًا؟

السؤال 2 من 3

mask = orders["shipping_fee"] == 0. ماذا تعيد mask.mean()؟

السؤال 3 من 3

تريد الطلبات العشرة ذات أعلى رسوم شحن، والأحدث أولًا بين الرسوم المتساوية. أيّ استدعاء هو الصحيح؟

تدريب

تمرين Python

اعزل الربع الرابع من 2025

باستخدام orders (مع تحليل order_date مسبقًا): اجعل q4 الطلبات المقدَّمة من 1 أكتوبر إلى 31 ديسمبر 2025 التي لم تُلغَ. واجعل coupon_share حصة طلبات q4 التي استخدمت كوبونًا، مقرّبة إلى 3 منازل عشرية. واجعل marketplace_coupons عدد الطلبات في الجدول كله التي جاءت عبر القناة "marketplace" واستخدمت كوبونًا. واجعل latest_ids قائمة بأرقام order_id لأحدث 3 طلبات في q4، الأحدث أولًا.

ملفات البيانات: orders.csv

import pandas as pd

orders = pd.read_csv("orders.csv", parse_dates=["order_date"])

# 1. Orders placed in Q4 2025 (October to December) that were NOT cancelled
q4 = None

# 2. Share of those Q4 orders that used any coupon, rounded to 3 decimals
coupon_share = None

# 3. In the whole table: number of marketplace orders that used a coupon
marketplace_coupons = None

# 4. order_id of the 3 most recent orders in q4, newest first, as a list
latest_ids = None
جارٍ تحميل المحرّر…

Ctrl/⌘ + Enter للتشغيل · يعمل في بيئة معزولة داخل متصفّحك. لا شيء يغادر جهازك.

(لا مخرجات)

الفحوص

  • في q4 642 طلبًا
  • لا طلبات ملغاة في q4 ولا شيء قبل أكتوبر 2025
  • coupon_share يساوي 0.231
  • 44 طلبًا من الـ marketplace استُخدم فيها كوبون
  • latest_ids تساوي [2017, 2735, 1550]