يا جماعة الخير، السلام عليكم ورحمة الله.
بتذكر قبل كم سنة، كنا في الفريق شغالين على منصة جديدة، فيها محتوى ضخم من مقالات وفيديوهات ودورات. كنا متحمسين كثير، والكل كان بيشتغل ليل نهار. أطلقنا المشروع، والأمور كانت ماشية، لكن بعد فترة بلشت توصلنا ملاحظات من المستخدمين، وأكثر ملاحظة كانت تتكرر: “التوصيات اللي بتطلعلي ما إلها دخل فيي!”، واحد من الشباب بعتلنا مرة: “يا جماعة الخير، أنا مهتم بالبرمجة، ليش بترشحولي دورة في الطبخ؟ هو أنا وجهي وجه طبخ؟”.
في البداية، دافعنا عن النظام تبعنا. قلنا يمكن المستخدمين الجداد لسا ما عرفناهم منيح. لكن مع الوقت، صارت الشكوى عامة. قعدت مع حالي ليلة، فتحت لوحة التحكم وقعدت أحلل البيانات. الصدمة كانت إنه نظام التوصيات تبعنا كان أبسط من البساطة؛ كان يا دوب يرشح الأشياء الأكثر شعبية للكل. يعني لو مقال عن “تربية الصقور” صار تريند، كل المستخدمين رح يشوفوه توصية أولى، سواء كان مهندس برمجيات أو طبيب بيطري. كانت توصياتنا، بكل معنى الكلمة، مجرد “ضربة حظ”. إما بتصيب أو بتخيب، وأغلب الوقت كانت تخيب.
هون قررنا إنه لازم نغير كل شي. كان لازم ننتقل من نظام “مقاس واحد للجميع” لنظام بيفهم كل مستخدم لحاله. وهيك بلشت رحلتنا الحقيقية مع ما يسمى بـ “الترشيح التشاركي” أو الـ Collaborative Filtering، الأداة اللي أنقذتنا من بحر المحتوى الضايع ورجعت الثقة بيننا وبين مستخدمينا.
ما هو الترشيح التشاركي (Collaborative Filtering)؟ وليش هو “أبو العريف” في عالم التوصيات؟
ببساطة شديدة، الترشيح التشاركي هو زي لما تسأل صحابك عن فيلم حلو تحضره. أنت ما بتسأل أي حدا بالشارع، بتسأل الناس اللي بتعرف إنه ذوقهم قريب من ذوقك.
هذا هو المبدأ بالضبط. الخوارزمية بتشتغل على فكرة إنه إذا كان في شخص (أ) عنده نفس ذوقك في تقييم الأشياء (أفلام، منتجات، مقالات)، فغالباً لو حب (أ) شي جديد أنت لسا ما شفته، احتمالية إنه يعجبك أنت كمان بتكون عالية جداً.
الخوارزمية بتبحث عن “أشباهك الأربعين” في عالم البيانات. بتلاقي المستخدمين اللي تفاعلوا مع المحتوى بنفس طريقتك (أعجبهم نفس الأشياء، كرهوا نفس الأشياء)، وبعدين بتشوف شو في أشياء حبوها هدول الناس وأنت لسا ما تفاعلت معها، وبتقترحها عليك. الفكرة عبقرية في بساطتها وقوتها.
أنواع الترشيح التشاركي: لكل مقامٍ مقال!
لما تعمقنا في الموضوع، اكتشفنا إنه الـ Collaborative Filtering مش نوع واحد، بل هو عائلة من الخوارزميات، وأهم نوعين فيها هما:
الترشيح التشاركي المعتمد على المستخدم (User-Based Collaborative Filtering)
هذا هو النهج الكلاسيكي والمباشر للفكرة. الخطوات تبعته كالتالي:
- خذ المستخدم الحالي (مثلاً “أحمد”).
- ابحث في كل قاعدة البيانات عن المستخدمين الأكثر شبهاً بـ “أحمد” بناءً على تقييماتهم السابقة.
- خذ العناصر (مقالات، أفلام…) اللي قيمها هؤلاء المستخدمون المشابهون تقييمًا عاليًا، ولكن “أحمد” لم يرها بعد.
- رشح هذه العناصر لـ “أحمد”.
مشكلته؟ في البداية طبقنا هذا النهج، لكن مع نمو قاعدة المستخدمين لمئات الآلاف، صارت عملية البحث عن “المستخدمين المشابهين” بطيئة جداً. كل ما يدخل مستخدم جديد، بدنا نلف على كل المستخدمين عشان نلاقي أشباهه. صرنا نسمع صراخ السيرفرات بالليل! يا جماعة، السيستم بطيء ومش عملي للمنصات الكبيرة.
الترشيح التشاركي المعتمد على العنصر (Item-Based Collaborative Filtering)
هون صارت النقلة النوعية معنا. بدل ما نبحث عن مستخدمين متشابهين، قررنا نبحث عن “عناصر” متشابهة. الفكرة تغيرت شوي وصارت هيك:
“الناس اللي حبوا العنصر (س)، حبوا كمان العنصر (ص)”.
بناءً على هذا المبدأ، الخوارزمية بتبني مصفوفة تشابه بين العناصر نفسها. فمثلاً، بتكتشف إنه 90% من الناس اللي بيشتروا “كتاب بايثون للمبتدئين”، بيشتروا كمان “كتاب هياكل البيانات والخوارزميات”.
فإذا أنت اشتريت الكتاب الأول، النظام ما رح يروح يدور على ناس بتشبهك، لأ! رح يروح مباشرة على مصفوفة تشابه العناصر ويشوف شو هي العناصر الأكثر شبهاً بالكتاب اللي اشتريته، ويرشحها إلك مباشرة. هذا النهج أسرع بكثير وأكثر استقرارًا، لأنه العلاقات بين العناصر ما بتتغير بسرعة زي أذواق المستخدمين.
من الحكي النظري للكود العملي: يلا نطبق سوا!
عشان الصورة توضح أكثر، خلينا نشوف مثال كود بسيط بلغة بايثون بيوضح فكرة الـ Item-Based CF. رح نستخدم مكتبات بسيطة زي `pandas` و `scikit-learn`.
# مرحباً يا جماعة، أنا أبو عمر، وهاد شوية كود لنشوف كيف الأمور بتمشي
import pandas as pd
from sklearn.metrics.pairwise import cosine_similarity
# 1. إنشاء بيانات وهمية (في الواقع هاي بتكون من قاعدة بياناتك)
# عنا مستخدمين (user_id) ومقالات (item_id) وتقييمات (rating)
data = {
'user_id': [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4],
'item_id': ['مقال أ', 'مقال ب', 'مقال ج', 'مقال أ', 'مقال د', 'مقال ب', 'مقال ج', 'مقال هـ', 'مقال أ', 'مقال ج', 'مقال هـ'],
'rating': [5, 4, 1, 5, 3, 5, 2, 5, 4, 3, 4]
}
df = pd.DataFrame(data)
# 2. تحويل البيانات لـ "مصفوفة المستخدم-العنصر" (user-item matrix)
user_item_matrix = df.pivot_table(index='user_id', columns='item_id', values='rating')
# التعامل مع القيم الفارغة (المستخدم ما قيّم هاد العنصر) - بنحط صفر
user_item_matrix = user_item_matrix.fillna(0)
print("مصفوفة المستخدم-العنصر:")
print(user_item_matrix)
# 3. حساب التشابه بين العناصر (Items) باستخدام التشابه الجيبي (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(user_id, num_recommendations=2):
print(f"n--- توصيات للمستخدم رقم {user_id} ---")
# جلب تقييمات المستخدم
user_ratings = user_item_matrix.loc[user_id]
# العناصر اللي لسا ما شافها المستخدم
unseen_items = user_ratings[user_ratings == 0].index
# حساب "الدرجة المتوقعة" لكل عنصر ما شافه
recommendations = {}
for item in unseen_items:
# أكثر عنصر مشابه لـ 'item' من اللي المستخدم شافهم وقيمهم عالي
# (هنا تبسيط، في الواقع الحساب أعقد)
similar_items = item_similarity_df[item].drop(item).nlargest(1)
# لو العنصر المشابه موجود في تقييمات المستخدم
if similar_items.index[0] in user_ratings[user_ratings > 0].index:
# الدرجة المتوقعة هي تشابه العنصرين
recommendations[item] = similar_items.values[0]
# فرز التوصيات حسب الدرجة الأعلى
sorted_recommendations = sorted(recommendations.items(), key=lambda x: x[1], reverse=True)
return sorted_recommendations[:num_recommendations]
# مثال: جلب توصيات للمستخدم رقم 2
# المستخدم 2 حب "مقال أ" و "مقال د"، الكود رح يشوف شو في مقالات بتشبههم
recs = get_recommendations(user_id=2)
print(f"nأفضل توصيات: {recs}")
نصائح من “الختيار”: كيف تتجنب الفخاخ اللي وقعنا فيها؟
بعد ما خضنا هاي التجربة، طلعت معنا شوية دروس عملية بتمنى تفيدكم وتختصر عليكم الطريق:
- مشكلة البداية الباردة (The Cold Start Problem): شو تعمل مع المستخدم الجديد اللي ما بنعرف عنه إشي؟ أو العنصر الجديد اللي ما حدا تفاعل معه؟ الحل: لا تترك الصفحة فاضية! ابدأ بترشيح المحتوى الأكثر شعبية أو الأكثر رواجًا حاليًا (Trending). حل آخر هو أن تسأل المستخدم عند التسجيل عن اهتماماته بشكل مباشر. ما تترك المستخدم الجديد “صافن” في الشاشة.
- قابلية التوسع (Scalability) هي المفتاح: زي ما حكيت، الـ User-based CF ما رح يفيدك على المدى الطويل إذا مشروعك كبير. فكر من البداية بالـ Item-based CF أو تقنيات أكثر تقدمًا مثل تفكيك المصفوفات (Matrix Factorization) مثل SVD. هاي التقنيات بتتعامل مع البيانات المتفرقة (Sparse data) بشكل أفضل وبتكون أسرع بكثير.
- البيانات، ثم البيانات، ثم البيانات: جودة توصياتك من جودة بياناتك. نظّف بياناتك أول بأول. مش بس التقييمات الصريحة (الـ 5 نجوم) مهمة. التفاعلات الضمنية (Implicit feedback) مثل عدد مرات مشاهدة الصفحة، مدة البقاء فيها، هل المستخدم عمل “حفظ” أو “مشاركة”، كلها كنوز من البيانات بتعطيك فكرة أدق عن اهتماماته.
- لا تكن مملًا (Serendipity): أحسن أنظمة التوصية هي اللي بتوازن بين الدقة والمفاجأة. لو ضليت أرشحلك أشياء بتشبه اللي أنت بتحبه 100%، مع الوقت رح تمل. لازم بين كل فترة وفترة “نكسر الروتين” ونرشحلك شي من فئة مختلفة تمامًا لكنها رائجة، أو عنصر بتقييم عالي لكنه مش من ضمن دائرة اهتمامك المباشرة. فاجئ المستخدم، خليه يحكي “والله ما خطرتلي هاي!”.
الخلاصة: من ضربة حظ… إلى علم وفن 🚀
رحلتنا في تحسين نظام التوصيات علمتنا درس مهم: الذكاء الاصطناعي مش عصا سحرية. هو علم، وأدوات، وفن في التطبيق. الانتقال من توصيات عشوائية لنظام ذكي يعتمد على الترشيح التشاركي ما كان مجرد تغيير في الكود، بل كان تغيير في طريقة تفكيرنا وفهمنا للمستخدم.
الترشيح التشاركي، سواء كان معتمدًا على المستخدم أو العنصر، هو حجر أساس في أي منصة حديثة تسعى لتقديم تجربة شخصية. هو الجسر اللي بيربط المستخدم بالمحتوى الهائل اللي ممكن يضيع فيه.
نصيحتي الأخيرة لكل مطور أو صاحب مشروع: لا تستهينوا بقوة التوصيات الجيدة. استثمروا فيها الوقت والجهد، لأنها بتحول المستخدم من زائر عابر إلى صديق وفيّ للمنصة. الموضوع مش سحر، الموضوع علم وممارسة. يلا يا جماعة، شدوا حيلكم ورجونا إبداعاتكم!