قصة “عمر” وموقع الأفلام العنيد
قبل عدة سنوات، كان ابني عمر، وهو في بداية مراهقته، مولعاً بالأفلام. في إحدى الأمسيات، وجدته يتأفف أمام شاشة الحاسوب وهو يقول بلهجته الفلسطينية الطفولية: “يا بيي، زهقت! هالموقع كل مرة بقترح عليّ أفلام ما إلها دخل باللي بحبه!”. نظرت إلى الشاشة، فوجدت أن الموقع يقترح عليه أفلاماً رومانسية كوميدية، بينما كان هو قد أنهى لتوه مشاهدة سلسلة أفلام “سيد الخواتم” الملحمية.
كانت المشكلة واضحة. نظام التوصيات في ذلك الموقع كان بدائياً جداً، يعتمد على “الأكثر مشاهدة” أو “الأحدث إضافة”. لم يكن هناك أي “ذكاء” حقيقي، أي فهم لشخصية عمر وتفضيلاته. كانت التوصيات عشوائية، باردة، وغير شخصية على الإطلاق. هذا الموقف البسيط ذكرني بمشروع عملت عليه في بداياتي، حيث كنا نعاني من شكاوى المستخدمين من رداءة التوصيات في متجر إلكتروني ناشئ. كانت تجربة محبطة للمستخدم ولنا كمطورين.
هنا يكمن جوهر حديثنا اليوم. كيف انتقلنا من هذا “الجحيم” من التوصيات العشوائية إلى العالم الذكي الذي نعيشه اليوم، حيث يبدو أن نتفليكس ويوتيوب وسبوتيفاي يقرؤون أفكارنا؟ الجواب يكمن في مفهوم ثوري وبسيط في آن واحد: الفلترة التشاركية (Collaborative Filtering).
ما هي الفلترة التشاركية (Collaborative Filtering)؟
ببساطة شديدة، تقوم الفلترة التشاركية على مبدأ اجتماعي قديم نعرفه جميعاً: “الطيور على أشكالها تقع”. الفكرة هي أنه إذا كان هناك شخص يتفق معك في أذواقك (أحب نفس الأفلام التي أحببتها، أو اشترى نفس الكتب التي اشتريتها)، فمن المرجح جداً أن يعجبك شيء آخر أحبه هو ولم تجربه أنت بعد.
الفلترة التشاركية لا تحتاج إلى معرفة أي شيء عن محتوى المنتجات نفسها (مثل نوع الفيلم أو مؤلف الكتاب). كل ما يهمها هو سلوك المستخدمين وتفاعلاتهم. وهذا هو سر قوتها وبساطتها.
بدلاً من تحليل خصائص الفيلم (أكشن، كوميدي، دراما)، يقوم النظام بتحليل سلوكك وسلوك ملايين المستخدمين الآخرين للعثور على “أشباهك” أو “جيرانك” في الذوق، ثم يقدم لك توصيات بناءً على ما أحبه هؤلاء “الجيران”.
كيف تعمل هذه الخوارزميات؟ “سحر” ما وراء الكواليس
هناك طريقتان رئيسيتان لتطبيق الفلترة التشاركية، ولكل منهما فلسفتها الخاصة.
النوع الأول: الفلترة التشاركية المعتمدة على المستخدم (User-Based CF)
هذه هي الطريقة الكلاسيكية والأكثر بديهية. تخيل أنك “أنت” والنظام يريد أن يوصي لك بفيلم جديد. الخطوات التي يتبعها هي كالتالي:
- البحث عن “توأمك” الرقمي: يبحث النظام عن المستخدمين الذين قيموا نفس الأفلام التي قيمتها بشكل مشابه. هؤلاء هم “جيرانك” أو “أشباهك”.
- استعارة أذواقهم: ينظر النظام إلى الأفلام التي شاهدها هؤلاء “الجيران” وأعطوها تقييمات عالية، ولكنك لم تشاهدها بعد.
- تقديم التوصية: يرشح لك هذه الأفلام، على افتراض أنك ستحبها أيضاً.
على سبيل المثال، إذا كنت أنت ومستخدم آخر اسمه “خالد” قد أحببتما أفلام “Inception” و “The Dark Knight”، ثم شاهد خالد فيلم “Interstellar” وأعطاه 5 نجوم، فإن النظام سيقوم بترشيح فيلم “Interstellar” لك بقوة.
المشكلة؟ هذه الطريقة تصبح بطيئة جداً ومكلفة حسابياً مع ازدياد عدد المستخدمين. تخيل أن عليك مقارنة كل مستخدم جديد بملايين المستخدمين الآخرين في كل مرة! كما أنها تعاني من مشكلة “البداية الباردة” (Cold Start) مع المستخدمين الجدد الذين ليس لديهم أي تقييمات بعد.
النوع الثاني: الفلترة التشاركية المعتمدة على العنصر (Item-Based CF)
هنا نغير زاوية النظر. بدلاً من البحث عن مستخدمين مشابهين لك، نبحث عن “عناصر” (Items) مشابهة للعناصر التي أحببتها. هذه الطريقة، التي اشتهرت بها أمازون، تتبع الخطوات التالية:
- بناء مصفوفة تشابه العناصر: يقوم النظام بحساب مدى تشابه كل عنصرين مع بعضهما البعض بناءً على تقييمات المستخدمين. على سبيل المثال، إذا كان معظم الأشخاص الذين اشتروا “كتاب تعلم بايثون” قد اشتروا أيضاً “كتاب خوارزميات تعلم الآلة”، فهذا يعني أن هذين الكتابين “متشابهان” من منظور سلوك المستخدم.
- فهم تفضيلاتك الحالية: ينظر النظام إلى العناصر التي تفاعلت معها مؤخراً أو أعطيتها تقييماً عالياً (مثلاً، فيلم شاهدته للتو).
- تقديم التوصية: يرشح لك العناصر الأكثر شبهاً بتلك التي أحببتها. وهذا هو سبب ظهور عبارة “العملاء الذين اشتروا هذا المنتج اشتروا أيضاً…”
هذه الطريقة أكثر كفاءة وقابلية للتوسع (Scalability)، لأن علاقات التشابه بين العناصر أكثر استقراراً من علاقات التشابه بين المستخدمين. أذواق الناس تتغير، لكن حقيقة أن “الجزء الأول” و “الجزء الثاني” من فيلم ما مرتبطان ببعضهما البعض لا تتغير كثيراً.
تحديات الفلترة التشاركية وكيف نتغلب عليها
رغم فعاليتها، تواجه هذه الخوارزميات بعض التحديات الكلاسيكية في عالم تعلم الآلة.
- مشكلة البداية الباردة (The Cold Start Problem): ماذا نفعل مع مستخدم جديد ليس له سجل؟ أو منتج جديد لم يقيمه أحد؟
- نصيحة أبو عمر: هنا لا مفر من استخدام حلول بسيطة في البداية. يمكننا أن نعرض له العناصر “الأكثر شعبية” أو “الأعلى تقييماً” بشكل عام. الحل الأفضل هو أن نسأله مباشرة عن بعض تفضيلاته أثناء عملية التسجيل (Onboarding)، كأن يختار بعض الأنواع الموسيقية أو الأفلام المفضلة لديه.
- مشكلة قلة البيانات (Data Sparsity): مصفوفة المستخدمين-العناصر غالباً ما تكون فارغة جداً (Sparse). معظم المستخدمين لم يتفاعلوا إلا مع عدد قليل جداً من العناصر المتاحة.
- نصيحة أبو عمر: هنا يأتي دور تقنيات أكثر تقدماً مثل “تحليل المصفوفات” (Matrix Factorization)، وأشهرها خوارزمية SVD. الفكرة هي تحويل المصفوفة الضخمة الفارغة إلى مصفوفتين أصغر حجماً تصفان “السمات الكامنة” (Latent Features) للمستخدمين والعناصر. مثلاً، قد تكتشف الخوارزمية لوحدها وجود سمة كامنة مثل “أفلام أكشن من بطولة توم كروز” دون أن نخبرها بذلك صراحةً، وتربط المستخدمين الذين يحبون هذه السمة بالأفلام التي تنتمي إليها.
مثال عملي بسيط: لنبني نظام توصية أفلام
دعونا نطبق ما تعلمناه بمثال بايثون بسيط باستخدام مكتبتي pandas و scikit-learn لتوضيح فكرة الـ Item-Based CF.
import pandas as pd
from sklearn.metrics.pairwise import cosine_similarity
# 1. بيانات وهمية (مستخدمون وتقييماتهم للأفلام من 1 إلى 5)
data = {
'user': ['أحمد', 'سارة', 'علي', 'أحمد', 'سارة', 'علي', 'فاطمة'],
'movie': ['فيلم أ', 'فيلم أ', 'فيلم ب', 'فيلم ب', 'فيلم ج', 'فيلم ج', 'فيلم أ'],
'rating': [5, 4, 2, 5, 5, 4, 5]
}
df = pd.DataFrame(data)
# 2. إنشاء مصفوفة المستخدمين-العناصر (User-Item Matrix)
user_item_matrix = df.pivot_table(index='user', columns='movie', values='rating')
# ملء القيم الفارغة (NaN) بـ 0، مما يعني أن المستخدم لم يقيم الفيلم
user_item_matrix = user_item_matrix.fillna(0)
print("مصفوفة المستخدمين-العناصر:")
print(user_item_matrix)
# 3. حساب التشابه بين العناصر (الأفلام) باستخدام تشابه جيب التمام (Cosine Similarity)
# نحتاج إلى تبديل المصفوفة (Transpose) لجعل الأفلام هي الصفوف
item_similarity_df = pd.DataFrame(
cosine_similarity(user_item_matrix.T),
index=user_item_matrix.columns,
columns=user_item_matrix.columns
)
print("nمصفوفة تشابه العناصر:")
print(item_similarity_df)
# 4. بناء دالة لتقديم التوصيات
def get_recommendations(movie_name, user_rating):
# الحصول على الأفلام المشابهة للفيلم المُدخل وضربها في تقييم المستخدم
# الفكرة: إذا أحببت الفيلم (تقييم عالٍ)، فستكون التوصيات للأفلام المشابهة له أقوى
similar_scores = item_similarity_df[movie_name] * (user_rating - 2.5) # نطرح 2.5 لجعل التقييمات السلبية تؤثر سلباً
similar_scores = similar_scores.sort_values(ascending=False)
return similar_scores
# مثال: لنفترض أن مستخدماً جديداً شاهد "فيلم أ" وأعطاه 5 نجوم
print("nتوصيات لمستخدم أحب 'فيلم أ' بتقييم 5:")
recommendations = get_recommendations('فيلم أ', 5)
print(recommendations[recommendations.index != 'فيلم أ']) # استبعاد الفيلم نفسه من التوصيات
هذا الكود، على بساطته، يوضح جوهر الفكرة. في الواقع، نستخدم بيانات أضخم بكثير وخوارزميات أكثر تعقيداً، لكن المبدأ يظل واحداً.
الخلاصة: من الضجيج إلى التناغم 🚀
لقد قطعت أنظمة التوصية شوطاً طويلاً. الفلترة التشاركية كانت القفزة النوعية التي أنقذتنا من التوصيات العشوائية والمزعجة. لقد حولت تجربة المستخدم من رحلة بحث مرهقة إلى حوار ذكي وشخصي بين المستخدم والمنصة. هي ليست “سحراً”، بل هي تطبيق جميل لمبدأ اجتماعي بسيط، مدعوم بالبيانات والرياضيات.
نصيحتي الأخيرة لك كمطور أو مهتم بهذا المجال: لا تنبهر بالخوارزميات المعقدة والشبكات العصبية العميقة منذ البداية. ابدأ بفهم وتطبيق خوارزمية بسيطة مثل Item-Based CF. ستتفاجأ من قوة النتائج التي يمكنك تحقيقها “بشغل مرتب” وبيانات نظيفة. الأساس المتين هو ما تبنى عليه الأنظمة الأسطورية. يلا، شدّوا حيلكم!