البحث عن حوادث ومطالبات مماثلة. المقاييس والتحسين

في مقالة سابقة ، تحدثت عن محرك البحث لدينا لتطبيقات مماثلة . بعد إطلاقه ، بدأنا في تلقي الاستعراضات الأولى. أحب المحللون وأوصوا ببعض التوصيات ، وبعضهم لم يفعل.


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


تحت الخفض ، سأتحدث عن:


  • جمع ردود الفعل على التوصيات
  • تطوير مقاييس لتقييم جودة التوصيات
  • بناء دورة تحسين النموذج
  • تلقى رؤى ونموذج جديد

جمع ردود الفعل


سيكون من المثالي جمع تعليقات صريحة من المحللين: ما مدى ملاءمة التوصية لكل حادث من الحوادث المقترحة. سيتيح لنا ذلك فهم الوضع الحالي ومواصلة تحسين النظام استنادًا إلى المؤشرات الكمية.


تقرر تجميع المراجعات بتنسيق بسيط للغاية:


  • عدد الحوادث التي نقوم بتحليلها
  • رقم الحادث الموصى به
  • مراجعة التوصية: جيد / سيء

تم وضع "تصويت" (وهو مشروع صغير قبل طلبات GET مع المعلمات ، ووضع المعلومات في ملف) مباشرة في كتلة التوصيات بحيث يمكن للمحللين ترك ملاحظاتهم على الفور من خلال النقر ببساطة على أحد الروابط: "جيد" أو "سيء".


بالإضافة إلى ذلك ، من أجل استعراض بأثر رجعي للتوصية ، تم التوصل إلى حل بسيط للغاية:


  • لجزء كبير من البيانات التاريخية ، تم إطلاق نموذج ؛
  • تم تقديم التوصيات التي تم جمعها في شكل العديد من ملفات HTML المستقلة ، والتي تم فيها استخدام نفس "التصويت" ؛
  • تم تسليم الملفات المعدة للمحللين من أجل عرض نتائج 50-100 حادث.

لذلك كان من الممكن جمع البيانات على ما يقرب من 4000 زوجا من توصية الحادث.


تحليل المراجعة الأولية


كانت المقاييس الأولية "جيدة جدًا" - كانت حصة التوصيات "الجيدة" ، وفقًا للزملاء ، حوالي 25٪ فقط.


المشاكل الرئيسية للنموذج الأول:


  1. الحوادث المتعلقة بالمشكلات "الجديدة" التي تلقت توصيات غير ذات صلة من النظام ؛ اتضح أنه في غياب المصادفات في محتوى الاستئناف ، اختار النظام الحوادث القريبة من قسم الموظف المتصل.
  2. توصيات لحادث على نظام واحد وقعت حوادث من أنظمة أخرى. كانت الكلمات المستخدمة في النداء متشابهة ، لكنها وصفت مشاكل الأنظمة الأخرى وكانت مختلفة.

تم اختيار الطرق الممكنة لتحسين جودة التوصيات:


  • تعديل التكوين والوزن من سمات العلاج التي يتم تضمينها في ناقل النهائي
  • اختيار إعدادات vectorization TfidfVectorizer
  • اختيار المسافة "قطع" من التوصيات

تطوير معايير الجودة وطرق التقييم


للبحث عن نسخة محسنة من النموذج ، من الضروري تحديد مبدأ تقييم جودة نتائج النموذج. سيسمح لك ذلك بمقارنة النموذجين من الناحية الكمية واختيار الأفضل.


ما يمكن الحصول عليه من الاستعراضات التي تم جمعها


لدينا العديد من muples من النموذج: "الحادث" ، "الحادث الموصى به" ، "تقييم التوصية".


  • يتم تعيين "تصنيف التوصية" ( ت ) - ثنائي: "جيد" | ضعيف (1 / -1) ؛
  • "الحادث" و "الحادث الموصى به" هما مجرد أرقام حادث. عليها يمكنك العثور على الحادث في قاعدة البيانات.

وجود هذه البيانات ، يمكنك حساب:


  • n_inc_total - إجمالي عدد الحوادث التي توجد بها توصيات
  • n_inc_good - عدد الحوادث التي توجد بها توصيات "جيدة"
  • avg_inc_good - متوسط ​​عدد التوصيات "الجيدة" للحوادث
  • n_rec_total - إجمالي عدد التوصيات
  • n_rec_good - العدد الإجمالي للتوصيات "الجيدة"
  • pct_inc_good - حصة من الحوادث التي توجد بها توصيات "جيدة"
    pct_inc_good = n_inc_good / n_inc_total
  • pct_rec_good - الحصة الإجمالية للتوصيات "الجيدة"
    pct_rec_good = n_rec_good / n_rec_total

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


خذ كل "الحوادث" الفريدة من م ، وقودها من خلال النموذج الجديد.


نتيجة لذلك ، حصلنا على العديد من m * tuples: "الحادث" ، "الحادث الموصى به" ، "المسافة".
هنا ، "المسافة" هي المقياس المحدد في NearestNeighbor. في نموذجنا ، هذه هي مسافة جيب التمام. تتوافق القيمة "0" مع المصادفة الكاملة للمتجهات.


اختيار "مسافة قطع"


مع استكمال مجموعة التوصيات m * بمعلومات حول التقدير الحقيقي لـ v من المجموعة الأولية للتقديرات m ، نحصل على المراسلات بين المسافة d والتقدير الحقيقي v لهذا النموذج.


بعد تعيين ( d ، v ) ، يمكن للمرء اختيار مستوى القطع الأمثل t ، والذي بالنسبة لـ <<= t ستكون التوصية "جيدة" ، و d> t - "سيئة". يمكن تحقيق اختيار t بتحسين أبسط المصنف الثنائي v = -1 if d>t else 1 فيما يتعلق بـ hyperparameter t ، واستخدام ، على سبيل المثال ، AUC ROC كمقياس.


 #     class BinarizerClassifier(Binarizer): def transform(self, x): return np.array([-1 if _x > self.threshold else 1 for _x in np.array(x, dtype=float)]).reshape(-1, 1) def predict_proba(self, x): z = self.transform(x) return np.array([[0 if _x > 0 else 1, 1 if _x > 0 else 0] for _x in z.ravel()]) def predict(self, x): return self.transform(x) # #   : # -  , # -    m* # -   (d,v)  z_data_for_t # #   t b = BinarizerClassifier() z_x = z_data_for_t[['distance']] z_y = z_data_for_t['TYPE'] cv = GridSearchCV(b, param_grid={'threshold': np.arange(0.1, 0.7, 0.01)}, scoring='roc_auc', cv=5, iid=False, n_jobs=-1) cv.fit(z_x, z_y) score = cv.best_score_ t = cv.best_params_['threshold'] best_b = cv.best_estimator_ 

يمكن استخدام قيمة t التي تم الحصول عليها لتصفية التوصيات.


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


افتراض لمقارنة النماذج


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


ثم ، بالنظر إلى المؤشرات نفسها للتوصيات m * الخاصة بالنموذج الجديد ، يمكن مقارنتها بالمؤشرات المقابلة لـ m . استنادا إلى المقارنة ، يمكنك اختيار أفضل نموذج.


هناك طريقتان لمراعاة التوصيات "الجيدة" للمجموعة m * :


  1. بناءً على النتيجة التي تم العثور عليها: ضع في اعتبارك أن جميع التوصيات الواردة من m * مع d < t "جيدة" وأخذها في الاعتبار عند حساب المقاييس
  2. على أساس التقديرات الحقيقية المقابلة من المجموعة m : من التوصيات m * ، حدد فقط تلك التي يوجد لها تقدير صحيح بالقيمة m ، وتجاهل الباقي.

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


حدد خيارات مقارنة النموذج


عند اختيار نموذج جديد ، أريد تحسين المؤشرات مقارنةً بالنموذج الحالي:


  • متوسط ​​عدد التوصيات "الجيدة" لكل حادث ( avg_inc_good )
  • عدد الحوادث التي توجد بها توصيات "جيدة" ( n_inc_good ).

للمقارنة مع النموذج الأصلي ، سوف نستخدم علاقات هذه المعلمات من النموذج الجديد والنموذج الأصلي. وبالتالي ، إذا كانت نسبة المعلمة للنموذج الجديد والقديم أكثر من 1 ، يكون النموذج الجديد أفضل.


 benchmark_agv_inc_good = avg_inc_good* / avg_inc_good benchmark_n_inc_good = n_inc_good* / n_inc_good 

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


 composite = 2 / ( 1/benchmark_agv_inc_good + 1/benchmark_n_inc_good) 

نموذج جديد وتحسينه


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


 p = Pipeline( steps=[ ('grp', ColumnTransformer( transformers=[ ('text', Pipeline(steps=[ ('pp', CommentsTextTransformer(n_jobs=-1)), ("tfidf", TfidfVectorizer(stop_words=get_stop_words(), ngram_range=(1, 3), max_features=10000, min_df=0)) ]), ['short_description', 'comments'] ), ('area', OneHotEncoder(handle_unknown='ignore'), ['area'] ), ('dept', OneHotEncoder(handle_unknown='ignore'), ['u_impacted_department'] ), ('loc', OneHotEncoder(handle_unknown='ignore'), ['u_impacted_location'] ) ], transformer_weights={'text': 1, 'area': 0.5, 'dept': 0.1, 'loc': 0.1}, n_jobs=-1 )), ('norm', Normalizer()), ("nn", NearestNeighborsTransformer(n_neighbors=10, metric='cosine')) ], memory=None) 

من المتوقع أن تؤثر نماذج hyperparameters على أهداف النموذج. في بنية النموذج المحدد ، سوف نعتبر معلمات تشعبية:


  • معلمات vectorization TF-IDF - n-grams المستخدمة (ngram_range) ، حجم القاموس (max_features) ، الحد الأدنى للقيادة على المدى (min_df)
  • مساهمة المكون في المتجه النهائي - transformer_weights.

يتم أخذ القيم الأولية لمعلمات فرط تحديد اتجاه النص من النموذج السابق. يتم تحديد أوزان المكون الأولي بناءً على تقدير الخبراء.


دورة اختيار المعلمة


كيفية المقارنة وتحديد مستوى الاختلال ومقارنة النماذج التي تم تحديدها بالفعل. الآن يمكننا المضي قدما في التحسين من خلال اختيار المعلمات الفائقة.


دورة التحسين


 param_grid = { 'grp__text__tfidf__ngram_range': [(1, 1), (1, 2), (1, 3), (2, 2)], 'grp__text__tfidf__max_features': [5000, 10000, 20000], 'grp__text__tfidf__min_df': [0, 0.0001, 0.0005, 0.001], 'grp__transformer_weights': [{'text': 1, 'area': 0.5, 'dept': 0.1, 'loc': 0.1}, {'text': 1, 'area': 0.75, 'dept': 0.1, 'loc': 0.1}, {'text': 1, 'area': 0.5, 'dept': 0.3, 'loc': 0.3}, {'text': 1, 'area': 0.75, 'dept': 0.3, 'loc': 0.3}, {'text': 1, 'area': 1, 'dept': 0.1, 'loc': 0.1}, {'text': 1, 'area': 1, 'dept': 0.3, 'loc': 0.3}, {'text': 1, 'area': 1, 'dept': 0.5, 'loc': 0.5}], } for param in ParameterGrid(param_grid=param_grid): p.set_params(**param) p.fit(x) ... 

نتائج التحسين


يوضح الجدول نتائج التجارب التي تحققت فيها نتائج مثيرة للاهتمام - أعلى 5 أفضل وأسوأ قيم للمؤشرات المتحكم فيها.



يتم وضع علامة على الخلايا التي تحتوي على مؤشرات في الجدول على النحو التالي:


  • الأخضر الداكن هو أفضل مؤشر بين جميع التجارب
  • أخضر شاحب - قيمة المؤشر في أعلى 5
  • أحمر غامق - أسوأ مؤشر بين جميع التجارب
  • أحمر شاحب - المؤشر في أسوأ 5

تم الحصول على أفضل مؤشر مركب لنموذج مع المعلمات:


 ngram_range = (1,2) min_df = 0.0001 max_features = 20000 transformer_weights = {'text': 1, 'area': 1, 'dept': 0.1, 'loc': 0.1} 

أظهر نموذج مع هذه المعلمات تحسنا في المؤشر المركب مقارنة بالنموذج الأصلي 24 ٪


بعض الملاحظات والاستنتاجات


وفقًا لنتائج التحسين:


  1. يبدو أن استخدام ngram_range = (1,3) ( ngram_range = (1,3) ) له ما يبرره. أنها تضخيم القاموس وزيادة طفيفة دقة مقارنة مع bigrams.


  2. سلوك مثير للاهتمام عند إنشاء قاموس باستخدام ngram_range = (2,2) فقط ( ngram_range = (2,2) ): تزداد "دقة" التوصيات ، ويتناقص عدد التوصيات الموجودة. تماما مثل التوازن الدقة / استدعاء في المصنفات. ويلاحظ وجود سلوك مماثل في اختيار مستوى القطع t - بالنسبة إلى الشركات الكبرى ، فإن "المخروط" الأضيق للقطع وقطع أفضل للتوصيات "الجيدة" و "السيئة" هي سمات مميزة.


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


  4. يتم الحصول على نتائج جيدة عندما يتم تضمين سمة الحادث المسؤولة عن "المنطقة" في المتجه النهائي مع وزن يساوي أو بالقرب من مكون النص. تؤدي القيم المنخفضة إلى زيادة نسبة التوصيات "السيئة" نظرًا لإيجاد كلمات مماثلة في المستندات من مناطق أخرى. لكن علامات موقع العميل لا تؤثر على نتائج التوصيات جيدًا في حالتنا.



ظهرت بعض الأفكار الجديدة:


  • إضافة مكون "وقت" بحيث تكون للحوادث الأخيرة الأسبقية على الحوادث المماثلة.
  • انظر كيف سيؤثر إدخال المعلمة max_df - على الرغم من أنه مع tf-idf ، يجب ألا يكون للكلمات العامة بالنسبة للجسم وزن كبير ، بحكم التعريف.
  • أخيرًا ، جرب طرقًا أخرى لتوجيه المحتوى ، على سبيل المثال ، استنادًا إلى تحويل كلمة إلى متجه ، أو بناءً على مجموعة من طرق عرض tf-idf باستخدام الشبكات.

Source: https://habr.com/ru/post/ar472772/


All Articles