الوحدة 5 · الإجابة عن أسئلة حقيقية
الإحصاء الوصفي والتوزيعات
18 دقراءة 4 دتمرين Python
الدرس في لمحة
صِف عمودًا رقميًا بصدق باستخدام الوسيط والمئينات والتشتّت، وتعرّف على التوزيعات الملتوية والقيم الشاذة، واقرأ الارتباطات دون أن تخلط بينها وبين الأسباب.
- 1المتوسط والوسيط والمئينات
- 2الشكل دون رسم بياني
- 3القيم الشاذة: ضع علامة ثم قرّر
- 4الارتباط: التحرّك معًا ليس تسبّبًا
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
يسألك أحدهم: “ما الطلب النموذجي في Cartwheel؟” فتحسب المتوسط، 228 دولارًا، وتقول ذلك. ثم يصمّم فريق التسويق حدًّا للشحن المجاني حول 228 دولارًا، فيكتشف أن ثلثي الطلبات لا تصل إليه أبدًا. كان المتوسط صحيحًا والإجابة خاطئة، لأن قيم الطلبات ليست موزّعة بالتساوي حول متوسطها. وصف البيانات بصدق يعني وصف شكلها، لا مركزها فقط.
المتوسط والوسيط والمئينات
import pandas as pd
items = pd.read_csv("order_items.csv")
orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
items["revenue"] = items["quantity"] * items["unit_price"] * (1 - items["discount"])
orders = orders.merge(items.groupby("order_id", as_index=False)["revenue"].sum(), on="order_id", validate="one_to_one")
orders = orders[orders["status"] != "cancelled"]
value = orders["revenue"]
print(value.describe(percentiles=[0.1, 0.25, 0.5, 0.75, 0.9, 0.99]).round(2))
print("skew:", round(value.skew(), 2))اقرأها من الوسط إلى الخارج. الوسيط (median) (50%) هو 147 دولارًا: نصف الطلبات كلها أصغر منه. ويقول الرُّبيعان إن النصف الأوسط من الطلبات يقع بين 68 و303 دولارات. المئين التسعون 505 والمئين التاسع والتسعون 1,168، بينما الحد الأقصى 2,117. أما المتوسط (mean)، 228، فيقع فوق الوسيط بكثير بسبب ذلك الذيل الأيمن الطويل، ويؤكّد ذلك الالتواء الموجب (skew) البالغ 2.43. للقيمة النموذجية في البيانات الملتوية، اذكر الوسيط؛ وللمجاميع والتوقّعات، المتوسط هو الرقم الصحيح، لأن المتوسط × العدد = المجموع.
std، أي الانحراف المعياري، يساوي 241 دولارًا، أكبر من الوسيط نفسه. هذه علامة أخرى على توزيع (distribution) منتشر وملتوٍ؛ وفي هذه الحالة تصف المئينات التشتّت أفضل بكثير من “المتوسط زائد أو ناقص انحراف معياري واحد”.
الشكل دون رسم بياني
تعدّ value_counts مع الفئات عدد القيم التي تقع في كل نطاق، وهذا مدرّج تكراري في صيغة نصية:
import pandas as pd
items = pd.read_csv("order_items.csv")
orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
items["revenue"] = items["quantity"] * items["unit_price"] * (1 - items["discount"])
orders = orders.merge(items.groupby("order_id", as_index=False)["revenue"].sum(), on="order_id", validate="one_to_one")
orders = orders[orders["status"] != "cancelled"]
print(orders["revenue"].value_counts(bins=[0, 50, 100, 200, 400, 800, 3000]).sort_index())معظم الطلبات تقع بين 50 و400 دولار، وذيل يرقّ تدريجيًا يمتد إلى ما بعد 800. لاحظ أن النطاقات تتّسع كلما اتجهت يمينًا؛ النطاقات المتساوية العرض بمقدار 100 دولار كانت ستضغط كل شيء تقريبًا في الأعمدة الأولى.
القيم الشاذة: ضع علامة ثم قرّر
قاعدة عملية شائعة تضع علامة على القيم التي تبعد عن الرُّبيعين أكثر من 1.5 ضعف المدى الرُّبيعي (IQR، المسافة بين الرُّبيعين):
import pandas as pd
items = pd.read_csv("order_items.csv")
orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
items["revenue"] = items["quantity"] * items["unit_price"] * (1 - items["discount"])
orders = orders.merge(items.groupby("order_id", as_index=False)["revenue"].sum(), on="order_id", validate="one_to_one")
orders = orders[orders["status"] != "cancelled"]
value = orders["revenue"]
q1, q3 = value.quantile([0.25, 0.75])
upper = q3 + 1.5 * (q3 - q1)
big = value > upper
print(f"fence {upper:.2f}: {big.sum()} orders, {value[big].sum() / value.sum():.1%} of revenue")125 طلبًا فوق 656.62 دولارًا، وتجلب معًا 25.9% من الإيراد. هذه ليست أخطاء تُنظَّف: إنها طلبات متعددة العناصر من مكاتب وكراسٍ وأوزان رياضية، حقيقية ومهمة. قاعدة القيم الشاذة (outliers) تخبرك أين تنظر. أخطاء الإدخال، مثل مجموع ضاعت فاصلته العشرية، تُصلَح؛ والقيم المتطرّفة الحقيقية تبقى، وتتحقّق أنت من أن استنتاجك يصمد معها وبدونها.
العدسة نفسها عبر الزمن
يمكن مقارنة التوزيعات عبر الفترات أيضًا، وهذه المقارنة تحمل دليلًا لدراسة الحالة. إذا قفز إيراد الربع الرابع من 2025 لأن العملاء ملؤوا سلات شراء أكبر، فيجب أن يكون الطلب النموذجي قد كبر:
import pandas as pd
items = pd.read_csv("order_items.csv")
orders = pd.read_csv("orders.csv", parse_dates=["order_date"])
items["revenue"] = items["quantity"] * items["unit_price"] * (1 - items["discount"])
orders = orders.merge(items.groupby("order_id", as_index=False)["revenue"].sum(), on="order_id", validate="one_to_one")
orders = orders[orders["status"] != "cancelled"]
quarter = orders["order_date"].dt.to_period("Q")
print(orders.groupby(quarter)["revenue"].agg(["count", "median"]).round(1).tail(4))لم يكبر. بلغ وسيط الطلب في الربع الرابع من 2025 قيمة 151.70 دولارًا، أي أقل قليلًا من 159.20 في الربع الثالث، بينما تضاعف عدد الطلبات. أيًّا كان ما حدث في الربع الرابع، فقد تعلّق بعدد الطلبات التي وصلت، لا بحجمها. جدول واحد من الوسيطات استبعد بالفعل تفسيرًا شائعًا.
الارتباط: التحرّك معًا ليس تسبّبًا
تقيس corr() مدى قوة تحرّك عمودين رقميين معًا، من -1 (متعاكسان تمامًا) مرورًا بـ 0 (لا علاقة خطية) إلى 1 (متلازمان تمامًا). في churn.csv صف لكل عميل وعلَم churned للانصراف:
import pandas as pd
churn = pd.read_csv("churn.csv")
cols = ["tenure_days", "orders", "days_since_last_order", "support_tickets", "churned"]
print(churn[cols].corr().round(2)["churned"])
print(churn.groupby("churned")["days_since_last_order"].median())العملاء الذين انصرفوا مضت عليهم مدة أطول بكثير منذ آخر طلب: وسيط قدره 214 يومًا مقابل 46، وارتباط (correlation) قدره 0.45. هذا يجعل الفجوة إشارة تحذير جيدة. لكنه لا يبيّن أن الفجوة تسبّب الانصراف؛ فالعميل الذي فقد اهتمامه أصلًا يتوقّف عن الطلب وينصرف، والقياسان كلاهما يعكسان تلك الحقيقة الواحدة. عامل الارتباطات كخيوط تستحق التحقيق، واحتفظ بكلمة “يسبّب” للتجارب.
في التمرين تصف قيم طلبات Cartwheel بنفسك. وفي الدرس التالي تحوّل أرقامًا كهذه إلى رسوم بيانية.
أهم النقاط
- في البيانات الملتوية مثل قيم الطلبات، يقع المتوسط فوق الوسيط بكثير؛ أبلغ عن الوسيط (وبضعة مئينات) حين تصف القيمة النموذجية.
- تعطي
quantile([0.25, 0.75])الرُّبيعين؛ والقيم التي تبعد عنهما أكثر من 1.5 ضعف المدى الرُّبيعي تستحق نظرة، لا حذفًا تلقائيًا. value_counts(bins=[...])مدرّج تكراري (histogram) نصي سريع يبيّن شكل التوزيع دون رسم بياني.- قارن المجموعات بمتوسطها ووسيطها وحجمها معًا، كي لا يقود الاستنتاجَ طلبٌ كبير واحد أو مجموعة صغيرة جدًا.
- تقيس
corr()مدى تحرّك عمودين معًا؛ والارتباط القوي خيط يستحق التحقيق، وليس أبدًا دليلًا على أن أحدهما يسبّب الآخر.