سؤال

أحاول فرز مجموعة من المنتجات حسب تقييمات العملاء باستخدام نظام 5 نجوم.الموقع الذي أقوم بإعداد هذا من أجله لا يحتوي على الكثير من التقييمات ويستمر في إضافة منتجات جديدة لذلك عادةً ما يحتوي على عدد قليل من المنتجات ذات عدد منخفض من التقييمات.

لقد حاولت استخدام متوسط ​​التقييم بالنجوم ولكن هذه الخوارزمية تفشل عندما يكون هناك عدد قليل من التقييمات.

على سبيل المثال، سيظهر المنتج الذي حصل على تقييمات 3×5 نجوم بشكل أفضل من المنتج الذي حصل على تقييمات 100×5 نجوم وتقييمات 2×2 نجمة.

ألا يجب أن يظهر المنتج الثاني أعلى لأنه أكثر جدارة بالثقة من الناحية الإحصائية بسبب العدد الأكبر من التقييمات؟

هل كانت مفيدة؟

المحلول

قبل عام 2015، أدرجت قاعدة بيانات الأفلام على الإنترنت (IMDb) علنًا الصيغة المستخدمة لتصنيف أفلامهم أعلى 250 قائمة الأفلام.يقتبس:

تعطي صيغة حساب أفضل 250 عنوانًا تقييمًا تقدير بايزي صحيح:

weighted rating (WR) = (v ÷ (v+m)) × R + (m ÷ (v+m)) × C

أين:

  • R = المتوسط ​​للفيلم (المتوسط)
  • v = عدد الأصوات للفيلم
  • م = الحد الأدنى من الأصوات المطلوبة لإدراجك في قائمة أفضل 250 (حاليًا 25000)
  • C = متوسط ​​الأصوات عبر التقرير بأكمله (حاليًا 7.0)

بالنسبة لأفضل 250 صوتًا، يتم أخذ أصوات الناخبين العاديين فقط بعين الاعتبار.

ليس من الصعب أن نفهم.الصيغة هي:

rating = (v / (v + m)) * R +
         (m / (v + m)) * C;

والتي يمكن تبسيطها رياضيا إلى:

rating = (R * v + C * m) / (v + m);

المتغيرات هي:

  • R – التقييم الخاص بالعنصر.R هو متوسط ​​أصوات العنصر.(على سبيل المثال، إذا لم يكن للعنصر أي أصوات، فإن R الخاص به هو 0.إذا أعطاها شخص ما 5 نجوم، يصبح R 5.إذا أعطاه شخص آخر نجمة واحدة، يصبح R 3، أي المتوسط [1, 5].وما إلى ذلك وهلم جرا.)
  • ج- متوسط ​​تقييم العنصر.ابحث عن R لكل عنصر في قاعدة البيانات، بما في ذلك العنصر الحالي، وخذ متوسطها؛هذا هو ج.(لنفترض أن هناك 4 عناصر في قاعدة البيانات، وتقييماتها هي [2, 3, 5, 5].C هو 3.75، متوسط ​​هذه الأرقام.)
  • v – عدد الأصوات للعنصر .(على سبيل المثال، إذا قام 5 أشخاص بالإدلاء بأصواتهم على عنصر ما، فإن v يساوي 5.)
  • م - المعلمة القابلة للضبط.يعتمد مقدار "التجانس" المطبق على التصنيف على عدد الأصوات (v) بالنسبة إلى m.اضبط m حتى ترضيك النتائج.ولا تسيء تفسير وصف IMDb لـ m على أنه "الحد الأدنى من الأصوات المطلوبة لإدراجها" - فهذا النظام قادر تمامًا على تصنيف العناصر ذات الأصوات الأقل من m.

كل ما تفعله الصيغة هو:أضف عدداً من الأصوات الوهمية، قيمة كل منها C، قبل حساب المتوسط.في البداية، عندما لا تكون هناك بيانات كافية (أي.عدد الأصوات أقل بشكل كبير من م)، وهذا يؤدي إلى ملء الفراغات ببيانات متوسطة.ومع ذلك، مع تراكم الأصوات، ستختفي الأصوات الوهمية في نهاية المطاف أمام الأصوات الحقيقية.

في هذا النظام، لا تتسبب الأصوات في تقلب التصنيف بشكل كبير.وبدلا من ذلك، فإنهم فقط يزعجونها قليلا في اتجاه ما.

عندما يكون هناك صفر من الأصوات، توجد فقط الأصوات الوهمية، وجميعها من النوع C.وهكذا، يبدأ كل عنصر بتقييم C.

أنظر أيضا:

نصائح أخرى

يرى هذه الصفحة لإجراء تحليل جيد لأنظمة التصنيف القائمة على النجوم، و هذا للحصول على تحليل جيد للأنظمة القائمة على التصويت الإيجابي/التصويت السلبي.

بالنسبة للتصويت لأعلى ولأسفل، فأنت تريد تقدير احتمالية أن تكون النتيجة "الحقيقية" (إذا كان لديك تقييمات لا نهائية)، في ضوء التقييمات التي حصلت عليها، أكبر من بعض الكمية (مثل، على سبيل المثال، الرقم المماثل لبعض العناصر الأخرى التي تريدها). إعادة الفرز ضد).

راجع المقالة الثانية للحصول على الإجابة، ولكن الاستنتاج هو أنك تريد استخدام ثقة ويلسون.تقدم المقالة المعادلة ونموذج كود روبي (يمكن ترجمته بسهولة إلى لغة أخرى).

يظهر إيفان ميلر نهج بايزي لتصنيف تصنيفات 5 نجوم:enter image description here

أين

  • nk هو عدد k-تقييمات النجوم،
  • sk هي "القيمة" (بالنقاط) لـ k نجوم,
  • N هو العدد الإجمالي للأصوات
  • K هو الحد الأقصى لعدد النجوم (على سبيل المثال.K=5، في نظام تصنيف 5 نجوم)
  • z_alpha/2 هل 1 - alpha/2 كمية التوزيع الطبيعي.إذا كنت تريد ثقة بنسبة 95% (استنادًا إلى التوزيع الخلفي بايزي) بأن معيار الفرز الفعلي لا يقل عن حجم معيار الفرز المحسوب، فاختر z_alpha/2 = 1.65.

في بايثون، يمكن حساب معيار الفرز باستخدام

def starsort(ns):
    """
    http://www.evanmiller.org/ranking-items-with-star-ratings.html
    """
    N = sum(ns)
    K = len(ns)
    s = list(range(K,0,-1))
    s2 = [sk**2 for sk in s]
    z = 1.65
    def f(s, ns):
        N = sum(ns)
        K = len(ns)
        return sum(sk*(nk+1) for sk, nk in zip(s,ns)) / (N+K)
    fsns = f(s, ns)
    return fsns - z*math.sqrt((f(s2, ns)- fsns**2)/(N+K+1))

على سبيل المثال، إذا كان العنصر يحتوي على 60 نجمة من فئة خمس نجوم، و80 نجمة من أربع نجوم، و75 نجمة من ثلاث نجوم، و20 نجمة من نجمتين، و25 نجمة واحدة، فإن تصنيف النجوم الإجمالي سيكون حوالي 3.4:

x = (60, 80, 75, 20, 25)
starsort(x)
# 3.3686975120774694

ويمكنك فرز قائمة بتقييمات 5 نجوم باستخدام

sorted([(60, 80, 75, 20, 25), (10,0,0,0,0), (5,0,0,0,0)], key=starsort, reverse=True)
# [(10, 0, 0, 0, 0), (60, 80, 75, 20, 25), (5, 0, 0, 0, 0)]

يوضح هذا التأثير الذي يمكن أن يحدثه المزيد من التقييمات على القيمة الإجمالية للنجمة.


ستجد أن هذه الصيغة تميل إلى إعطاء تصنيف إجمالي أقل قليلاً من التصنيف الإجمالي الذي أبلغت عنه مواقع مثل Amazon أو eBay أو Wal-Mart خاصة عندما يكون هناك عدد قليل من الأصوات (على سبيل المثال ، أقل من 300).هذا يعكس عدم اليقين العالي الذي يأتي مع عدد أقل من الأصوات.مع زيادة عدد الأصوات (إلى الآلاف) ، يجب أن تميل جميع صيغ التصنيف هذه إلى متوسط ​​التصنيف (المرجح).


نظرًا لأن الصيغة تعتمد فقط على توزيع الترددات لتصنيفات 5 نجوم للعنصر نفسه ، فمن السهل ذلك يجمع مراجعات من مصادر متعددة (أو،تحديث التصنيف العام في ضوء الأصوات الجديدة) عن طريق إضافة توزيعات التردد معًا.


على عكس صيغة IMDB ، لا تعتمد هذه الصيغة على متوسط ​​الدرجات عبر جميع العناصر ، ولا تعتمد على الحد الأدنى لقيمة قطع الأصوات.

علاوة على ذلك ، تستخدم هذه الصيغة توزيع التردد الكامل - وليس فقط متوسط ​​عدد النجوم وعدد الأصوات.ومن المنطقي أنه ينبغي أن يعامل عنصر يحتوي على عشرة نجوم وعشرة نجوم واحد على أنه يعاني من عدم اليقين أكثر من (وبالتالي لا يتم تصنيفه على أنه) عنصرًا يحتوي على عنصر من فئة 3 نجوم:

In [78]: starsort((10,0,0,0,10))
Out[78]: 2.386028063783418

In [79]: starsort((0,0,20,0,0))
Out[79]: 2.795342687927806

صيغة IMDb لا تأخذ هذا في الاعتبار.

يمكنك الفرز حسب الوسيط بدلا من المتوسط ​​الحسابي.في هذه الحالة، كلا المثالين لهما متوسط ​​5، لذلك سيكون لكل منهما نفس الوزن في خوارزمية الفرز.

يمكنك استخدام أ وضع لنفس التأثير، ولكن الوسيط ربما يكون فكرة أفضل.

إذا كنت ترغب في تعيين وزن إضافي للمنتج الحاصل على 100 تقييم من فئة 5 نجوم، فربما ترغب في استخدام نوع من الوضع المرجح، مع تعيين وزن أكبر للتقييمات بنفس المتوسط، ولكن مع المزيد من الأصوات الإجمالية.

حسنًا، اعتمادًا على مدى التعقيد الذي تريد تحقيقه، يمكن أن يكون لديك تقييمات مرجحة أيضًا بناءً على عدد التقييمات التي أجراها الشخص، وما هي تلك التقييمات.إذا قام الشخص بإجراء تقييم واحد فقط، فمن الممكن أن يكون هذا التقييم أقل من ذلك.أو إذا قام الشخص بتقييم العديد من الأشياء في الفئة أ، ولكن القليل منها في الفئة ب، وحصل على متوسط ​​تقييم 1.3 من أصل 5 نجوم، فيبدو أن الفئة أ قد تكون مثقلة بشكل مصطنع بسبب انخفاض متوسط ​​الدرجات لهذا المستخدم، و ينبغي تعديلها.

ولكن ما يكفي لجعلها معقدة.دعونا نجعل الأمر بسيطا.

بافتراض أننا نعمل مع قيمتين فقط، ReviewCount وAverageRating، لعنصر معين، سيكون من المنطقي بالنسبة لي أن أعتبر ReviewCount بمثابة قيمة "الموثوقية" بشكل أساسي.ولكننا لا نريد فقط خفض النتائج للعناصر ذات عدد المراجعة المنخفض:من المحتمل أن يكون التصنيف بنجمة واحدة غير موثوق به مثل تصنيف 5 نجوم واحد.إذن ما نريد القيام به هو على الأرجح المتوسط ​​نحو المنتصف:3.

لذا، أفكر بشكل أساسي في معادلة مثل X * AverageRating + Y * 3 = التقييم الذي نريده.لكي نجعل هذه القيمة صحيحة، نحتاج إلى X+Y لتساوي 1.نحتاج أيضًا إلى زيادة قيمة X مع زيادة عدد المراجعة... مع عدد المراجعة 0، يجب أن يكون x 0 (مما يعطينا معادلة "3")، ومع عدد المراجعة اللانهائي X يجب أن يكون 1 (مما يجعل المعادلة = متوسط ​​التقييم).

إذن ما هي معادلات X وY؟بالنسبة لمعادلة X، تريد أن يقترب المتغير التابع بشكل مقارب من 1 عندما يقترب المتغير المستقل من اللانهاية.مجموعة جيدة من المعادلات هي شيء من هذا القبيل:y = 1/(عامل^ratingCount) و (باستخدام حقيقة أن x يجب أن يكون مساوياً لـ 1-y) x = 1-(1/(عامل^ratingCount)

ثم يمكننا ضبط "العامل" ليناسب النطاق الذي نبحث عنه.

لقد استخدمت برنامج C# البسيط هذا لتجربة بعض العوامل:

        // We can adjust this factor to adjust our curve.
        double factor = 1.5;  

        // Here's some sample data
        double RatingAverage1 = 5;
        double RatingCount1 = 1;

        double RatingAverage2 = 4.5;
        double RatingCount2 = 5;

        double RatingAverage3 = 3.5;
        double RatingCount3 = 50000; // 50000 is not infinite, but it's probably plenty to closely simulate it.

        // Do the calculations
        double modfactor = Math.Pow(factor, RatingCount1);
        double modRating1 = (3 / modfactor)
            + (RatingAverage1 * (1 - 1 / modfactor));

        double modfactor2 = Math.Pow(factor, RatingCount2);
        double modRating2 = (3 / modfactor2)
            + (RatingAverage2 * (1 - 1 / modfactor2));

        double modfactor3 = Math.Pow(factor, RatingCount3);
        double modRating3 = (3 / modfactor3)
            + (RatingAverage3 * (1 - 1 / modfactor3));

        Console.WriteLine(String.Format("RatingAverage: {0}, RatingCount: {1}, Adjusted Rating: {2:0.00}", 
            RatingAverage1, RatingCount1, modRating1));
        Console.WriteLine(String.Format("RatingAverage: {0}, RatingCount: {1}, Adjusted Rating: {2:0.00}",
            RatingAverage2, RatingCount2, modRating2));
        Console.WriteLine(String.Format("RatingAverage: {0}, RatingCount: {1}, Adjusted Rating: {2:0.00}",
            RatingAverage3, RatingCount3, modRating3));

        // Hold up for the user to read the data.
        Console.ReadLine();

لذلك لا تكلف نفسك عناء نسخه، فهو يعطي النتيجة التالية:

RatingAverage: 5, RatingCount: 1, Adjusted Rating: 3.67
RatingAverage: 4.5, RatingCount: 5, Adjusted Rating: 4.30
RatingAverage: 3.5, RatingCount: 50000, Adjusted Rating: 3.50

شئ مثل هذا؟من الواضح أنه يمكنك ضبط قيمة "العامل" حسب الحاجة للحصول على نوع الترجيح الذي تريده.

إذا كنت تحتاج فقط إلى حل سريع ورخيص يعمل في الغالب دون استخدام الكثير من العمليات الحسابية، فإليك خيارًا واحدًا (بافتراض مقياس تقييم من 1 إلى 5)

SELECT Products.id, Products.title, avg(Ratings.score), etc
FROM
Products INNER JOIN Ratings ON Products.id=Ratings.product_id
GROUP BY 
Products.id, Products.title
ORDER BY (SUM(Ratings.score)+25.0)/(COUNT(Ratings.id)+20.0) DESC, COUNT(Ratings.id) DESC

من خلال إضافة 25 وتقسيمها على إجمالي التقييمات + 20، فإنك تضيف أساسًا 10 أسوأ الدرجات وأفضل 10 درجات إلى إجمالي التقييمات ثم تقوم بالفرز وفقًا لذلك.

هذا لديه مشاكل معروفة.على سبيل المثال، فإنه يكافئ بشكل غير عادل المنتجات ذات الدرجات المنخفضة مع عدد قليل من التقييمات (مثل هذا الرسم البياني كما يوضح، فإن المنتجات ذات متوسط ​​درجة 1 وتقييم واحد فقط تحصل على 1.2 بينما تحصل المنتجات ذات متوسط ​​درجة 1 و1k+ تقييمات أقرب إلى 1.05).يمكنك أيضًا القول إنها تعاقب بشكل غير عادل المنتجات عالية الجودة ذات التقييمات القليلة.

يوضح هذا الرسم البياني ما يحدث لجميع التقييمات الخمسة التي تزيد عن 1-1000 تقييم:http://www.wolframalpha.com/input/?i=Plot3D%5B%2825%2Bxy%29/%2820%2Bx%29%2C%7Bx%2C1%2C1000%7D%2C%7By%2C0%2C6% 7د%5د

يمكنك رؤية الانخفاض للأعلى في أدنى التصنيفات، لكن بشكل عام، هذا تصنيف عادل، على ما أعتقد.يمكنك أيضًا النظر إلى الأمر بهذه الطريقة:

http://www.wolframalpha.com/input/?i=Plot3D%5B6-%28%2825%2Bxy%29/%2820%2Bx%29%29%2C%7Bx%2C1%2C1000%7D%2C%7By %2C0%2C6%7D%5D

إذا قمت بإسقاط قطعة من الرخام في معظم الأماكن في هذا الرسم البياني، فسوف تتجه تلقائيًا نحو المنتجات ذات الدرجات الأعلى والتقييمات الأعلى.

من الواضح أن العدد المنخفض من التقييمات يضع هذه المشكلة في عائق إحصائي.مع ذلك...

أحد العناصر الأساسية لتحسين جودة التقييم الإجمالي هو "تقييم المُقيّم"، أي.للاحتفاظ بعلامات تبويب للتقييمات التي قدمها كل "مقيم" معين (بالنسبة للآخرين).وهذا يسمح بوزن أصواتهم أثناء عملية التجميع.

الحل الآخر، وهو أكثر من مجرد حل، هو تزويد المستخدمين النهائيين بعدد (أو إشارة إلى نطاق منه) من الأصوات للبند الأساسي.

أحد الخيارات هو نظام يشبه نظام TrueSkill من Microsoft، حيث يتم تحديد النتيجة من خلاله mean - 3*stddev, حيث يمكن تعديل الثوابت.

بعد البحث لفترة من الوقت، اخترت نظام بايزي.إذا كان شخص ما يستخدم روبي، فإليك جوهرة له:

https://github.com/wbotelhos/rated

أوصي بشدة بكتاب برمجة الذكاء الجماعي من تأليف توبي سيغاران (OReilly) رقم ISBN 978-0-596-52932-1 الذي يناقش كيفية استخلاص بيانات ذات معنى من سلوك الحشود.الأمثلة موجودة في لغة بايثون، ولكن من السهل تحويلها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top