الوحدة 1 — صياغة مسألة التوصية
كثير من مشاريع التوصية تنطلق من قرار خاطئ لا يُلاحَظ في وقته: تُصاغ المسألة انحدارًا للنقاط، بينما ما يهمّ المستخدم فعلًا هو قائمة العشرة الأولى التي تظهر أمامه. هذه الوحدة تُبيّن الفرق بين الصياغتَين، وتُفصّل نوعَي الإشارة اللذين يُبنى عليهما كلّ ما يأتي بعد، وتُقدّم الشكل النادر لمصفوفة المستخدم والعنصر الذي يُميّز هذا المجال عن سائر التعلّم المُوجَّه.
تنبّؤ بالنقطة، أم ترتيب لقائمة؟
في التصفية التقليديّة للنقاط، كان الهدف تقدير نجمة بين واحدة وخمس بأصغر خطأ ممكن. المقياس المُستعمَل تاريخيًّا هو الجذر التربيعيّ لمتوسّط مربّع الخطأ RMSE، وهو ما دفعت شركة Netflix عليه مليون دولار في عام 2009. غير أنّ هذا التأطير يحمل عيبًا جوهريًّا: المستخدم لا يرى النقاط، بل يرى قائمة مرتّبة من عشرة عناصر تصعد أو تسقط في هذه القائمة. نموذج يُخفّض RMSE بضبطه للنقاط المتوسّطة (النجمتَين والثلاث نجوم) يظلّ عاجزًا عن ترتيب العناصر الاستثنائيّة في أعلى القائمة.
المقاييس السليمة هنا هي مقاييس الترتيب: الاستدعاء عند k، والدقّة عند k، وNDCG. سنأتي إليها بالتفصيل في الوحدة الثامنة، ويكفي أن نُثبّت الفكرة الآن: الهدف الحقيقيّ هو ترتيب أوّل عشرة عناصر بشكل صحيح، لا تقدير كلّ نقطة تقديرًا دقيقًا. وهذا الفرق يقلب اختيار الخسارة أثناء التدريب، ويُغيّر تفسير النتائج، وينفي عن RMSE قيمته المرجعيّة في الإنتاج.
التغذية الراجعة: صريحة وضمنيّة
تنقسم إشارات التفضيل قسمَين مختلفَين اختلافًا جذريًّا.
التغذي ة الراجعة الصريحة يعطيها المستخدم عن قصد: نجوم، إبهام لأعلى وإبهام لأسفل، تعليق. نقاؤها مغرٍ لكنّها نادرة، متحيّزة نحو التطرّف (يقيّم النّاس ما أحبّوه كثيرًا أو كرهوه كثيرًا)، وتصل بعد التفاعل بوقت طويل، أي بعد أن اتّخذ المستخدم قراره أصلًا.
التغذية الراجعة الضمنيّة تُستنبَط من الفعل: نقرة على الغلاف، تسجيل في دورة، عدد الدقائق المُشاهَدة، إتمام. غزيرة، وتصل في اللحظة، لكنّها مبهمة: نقرة تعني الاهتمام أو الفضول أو الخطأ. ولا يوجد فيها إشارة سلبيّة صريحة؛ غياب النقرة قد يكون رفضًا أو غيابًا عن الرؤية أو تشتّتًا. وأخطر ما فيها: مكان ظهور العنصر على الشاشة يُغيّر احتمال النقر أكثر بكثير من محتواه. سنعود إلى هذا تحيّز الموضع في الوحدة التاسعة.
في منصّة دورات مثل الخيط الأحمر لدينا، الإشارتان موجودتان: نجوم يضعها المتعلّم بعد الإتمام (صريحة، نحو 5% من التسجيلات)، وعدد الدقائق المُشاهَدة والإتمام (ضمنيّة، 100% من التسجيلات). التصميم السليم يُدمج الإشارتَين: الصريحة نادرة لكنّها موثوقة، الضمنيّة كثيرة لكنّها مبهمة.
المصفوفة النادرة: الشكل الأساسيّ للبيانات
يُمثَّل عالم التوصية بمصفوفة ذات سطرًا (المستخدمون) و عمودًا (العناصر). القيمة هي إشارة المستخدم على العنصر : نجمة، أو 1 إذا سُجّل في الدورة، أو غياب.
الفرق مع تعلّم الآلة الكلاسيكيّ صادم: هذه المصفوفة فارغة تقريبًا. على MovieLens 1M، من أصل عشرين مليون خانة ممكنة، توجد أقلّ من مليون قيمة معروفة، أي أقلّ من 5%. على منصّتنا الفرضيّة، 500 دورة × 50000 متعلّم = 25 مليون خانة، لكنّ عدد التسجيلات الفعليّة قد لا يتجاوز 200000، أي أقلّ من 1%. هذا الندرة الشديدة تُوجّه كلّ خيار خوارزميّ لاحقًا: البحث عن الجيران يحتاج تحسينًا ذكيًّا (الوحدة 2)، وتفكيك المصفوفة لا يمكن تنفيذه بـSVD كلاسيكيّ (الوحدة 3)، والنماذج العميقة تحتاج أخذ عيّنات سالبة (الوحدة 6).
النقطة الأدقّ من الندرة: الغياب ليس صفرًا. المتعلّم الذي لم يُسجَّل في دورة على AWS لم يقل «لا أريدها»؛ قد يكون لم يرها أصلًا. خلط الغياب مع التقييم السلبيّ خطأ منهجيّ يُنتج نماذج متحيّزة نحو الشعبيّة.
هدف تجاريّ حقيقيّ خلف كلّ مقياس
المقياس الحسابيّ خادم للهدف التجاريّ، لا العكس. على منصّة دورات، الأهداف التي رأيناها في مشاريع حقيقيّة:
- زيادة الإتمام (شركة تعليميّة B2B): ترتيب الدورات التي يُرجَّح أن يُتمّها المتعلّم، لا التي يبدؤها فحسب. الإشارة الرئيسة: نسبة الإتمام لا التسجيل.
- زيادة اكتشاف كاتالوغ طويل الذيل (منصّة ثقافيّة): تجنّب توصية الدورات الشعبيّة نفسها لكلّ مستخدم. المقياس المرافق: التغطية والتنوّع.
- زيادة الاشتراكات المتجدّدة (نموذج SaaS): توصية دورة تُقنِع المتعلّم بأنّ الاشتراك يستحقّ الشهر التالي. الأفق زمنيّ متأخّر.
هذه الأهداف الثلاثة تُنتج ثلاثة أنظمة توصية مختلفة على نفس البيانات. اختيار الخسارة، وطريقة أخذ العيّنات، ومقياس التقييم في الإنتاج، كلّها تنبع من هذا الاختيار الأوّليّ.
استكشاف عمليّ للبيانات
قبل بناء أيّ نموذج، ندرس شكل البيانات ونقيس الندرة. المثال أدناه على MovieLens 1M:
import pandas as pd
# تحميل الجدول: userId, movieId, rating, timestamp
ratings = pd.read_csv(
"ml-1m/ratings.dat",
sep="::",
engine="python",
names=["userId", "movieId", "rating", "timestamp"],
)
nb_users = ratings["userId"].nunique()
nb_items = ratings["movieId"].nunique()
nb_ratings = len(ratings)
sparsite = 1 - nb_ratings / (nb_users * nb_items)
print(f"المستخدمون: {nb_users}, العناصر: {nb_items}")
print(f"التقييمات: {nb_ratings}")
print(f"الندرة: {sparsite:.4f}") # حوالي 0.9553
# توزيع التقييمات لكلّ مستخدم: قنبلة قد تُخفي مشكلة تحيّز
par_user = ratings.groupby("userId").size()
print(f"وسيط التقييمات لكلّ مستخدم: {par_user.median()}")
print(f"1% أعلى المستخدمين يُقيّم {par_user.quantile(0.99):.0f} فيلمًا")
الوسيط يُظهر ما يفعله المستخدم النموذجيّ. أمّا الشريحة العليا (1% الأعلى) فتُنتج عادةً 20-30% من كلّ التفاعلات، وهذا تحيّز الناشط الذي سيُثقل النموذج نحو ذوق قلّة نشيطة إذا لم يُعالَج.
الخلاصة
- التوصية مسألة ترتيب لا انحدار، والمقاييس المرجعيّة مقاييس ترتيب لا RMSE.
- التغذية الراجعة الصريحة (نجوم) نادرة وموثوقة، والضمنيّة (نقرات، دقائق مُشاهَدة) غزيرة ومبهمة؛ كلّ نظام إنتاج جادّ يستعمل الاثنتَين.
- بيانات التوصية نادرة جدًّا (أقلّ من 5% من المصفوفة معروفة عادةً)، والغياب لا يعني تقييمًا سلبيًّا.
- كلّ اختيار خوارزميّ يبدأ من الهدف التجاريّ: الإتمام، أو التنوّع، أو التجديد، ينبع منه اختيار الخسارة والمقياس.
الوحدة التالية: التصفية التعاونيّة القائمة على الجوار، أوّل طريقة عمليّة لإنتاج توصية دون نموذج معقّد.