
قبل شهر ، أطلقت Lenta مسابقة تحدد فيها قبعة Talking Hat من Harry Potter المشاركين الذين يمكنهم الوصول إلى الشبكة الاجتماعية إلى واحدة من أربع كليات. المنافسة ليست سيئة ، والأسماء التي تبدو مختلفة يتم تحديدها من قبل كليات مختلفة ، ويتم توزيع الأسماء والألقاب الإنجليزية والروسية بطريقة مماثلة. لا أعرف ما إذا كان التوزيع يعتمد فقط على الأسماء والألقاب ، وما إذا كان عدد الأصدقاء أو العوامل الأخرى يؤخذ في الاعتبار بطريقة أو بأخرى ، ولكن هذه المسابقة اقترحت فكرة هذه المقالة: حاول تدريب المصنف من البداية ، والذي سيسمح للمستخدمين بالتوزيع على الكليات المختلفة.
في هذه المقالة ، سنقوم بعمل نموذج ML بسيط يوزع الأشخاص على أقسام هاري بوتر اعتمادًا على اسمهم ولقبهم ، بعد أن مروا بعملية بحث صغيرة باتباع منهجية CRISP . وبالتحديد نحن:
- نقوم بصياغة المشكلة.
- نحن نحقق في الأساليب الممكنة لحلها ونصوغ متطلبات البيانات (طرق الحل والبيانات) ؛
- سنقوم بجمع البيانات اللازمة (طرق الحل والبيانات) ؛
- سنقوم بدراسة مجموعة البيانات التي تم جمعها (البحث الاستكشافي) ؛
- استخراج الميزات من البيانات الأولية (هندسة الميزات) ؛
- دعونا نعلم نموذج التعلم الآلي (تقييم النموذج) ؛
- قارن النتائج التي تم الحصول عليها ، وتقييم جودة الحلول ، وإذا لزم الأمر ، كرر الفقرات 2-6 ؛
- نقوم بتعبئة الحل في خدمة يمكن استخدامها (الإنتاج).

قد تبدو هذه المهمة تافهة ، لذلك سنفرض قيودًا إضافية على العملية بأكملها (بحيث تستغرق أقل من ساعتين) وعلى هذه المقالة (بحيث يكون وقت قراءتها أقل من 15 دقيقة).
إذا كنت بالفعل منغمسًا في عالم علوم البيانات الرائع والرائع ولا ترى Kagglite باستمرار ، أو (لا سمح الله) ترغب في قياس طول Hadup الخاص بك أثناء الاجتماعات مع الزملاء ، فمن المرجح أن تبدو المقالة بسيطة وغير مهمة بالنسبة لك. علاوة على ذلك: جودة النماذج النهائية ليست القيمة الرئيسية لهذه المقالة. لقد حذرناكم. دعنا نذهب.
يتوفر أيضًا مستودع جيثوب مع الرمز المستخدم في المقالة للقراء الفضوليين. في حالة حدوث أخطاء ، يرجى فتح PR.
من الممكن حل مشكلة ليس لها معايير قرار واضحة لفترة طويلة إلى ما لا نهاية ، لذلك سنقرر على الفور أننا نريد الحصول على حل يسمح لنا بالحصول على إجابة "Gryffindor" أو "Ravenclaw" أو "Hufflepuff" أو "Slytherin" ردًا على السطر الذي تم إدخاله.
في الواقع ، نريد الحصول على صندوق أسود:
" " => [?] => Griffindor
وزعت القبعة السوداء الأصلية معالجات شابة على الأقسام حسب طبيعتها وصفاتها الشخصية. نظرًا لأن البيانات المتعلقة بالشخصية والشخصية وفقًا لظروف المشكلة ليست متاحة لنا ، فسوف نستخدم اسم ولقب المشارك ، وتذكر أنه في هذه الحالة يجب أن نوزع أحرف الكتاب على تلك الأقسام التي تتوافق مع أقسامها الأصلية من الكتاب. وسيغضب الفخاريون بالتأكيد إذا وزع قرارنا هاري على Hufflepuff أو Ravenclaw (ولكن يجب أن يرسل Harry إلى Gryffindor و Slytherin باحتمالية متساوية لنقل روح الكتاب).
بما أننا نتحدث عن الاحتمالات ، فإننا نقوم بإضفاء الطابع الرسمي على المشكلة بعبارات رياضية أكثر صرامة. من وجهة نظر Data Science ، نحل مشكلة التصنيف ، أي تخصيص كائن معين (سطر ، في شكل اسم ولقب) لفئة معينة (في الواقع أنها مجرد تسمية أو تسمية ، والتي يمكن أن تكون عددًا أو 4 متغيرات لها قيمة نعم / لا ) نحن نتفهم أنه في حالة هاري على الأقل ، سيكون من الصحيح إعطاء إجابتين: جريفندور وسليذرين ، لذا سيكون من الأفضل عدم التنبؤ بالكلية المحددة التي تحددها القبعة ، ولكن احتمال تخصيص شخص لهذه الكلية ، لذلك سيتم اتخاذ قرارنا في نوع من بعض الوظائف
المقاييس وتقييم الجودة
تتم صياغة المهمة والهدف ، سنفكر الآن في كيفية حلها لكن هذا ليس كل شيء. لبدء الدراسة ، تحتاج إلى إدخال مقاييس الجودة. بعبارة أخرى ، لتحديد كيفية مقارنة حلين مختلفين لبعضنا البعض.
كل شيء في الحياة جيد وبسيط - نحن نفهم بشكل بديهي أن كاشف البريد العشوائي يجب أن يمرر الحد الأدنى من الرسائل غير المرغوب فيها إلى الرسائل الواردة ، بالإضافة إلى تمرير الحد الأقصى من الأحرف الضرورية وبالتأكيد يجب ألا يرسل الرسائل الضرورية إلى البريد العشوائي.
في الواقع ، كل شيء أكثر تعقيدًا وتأكيد ذلك هو عدد كبير من المقالات التي تشرح كيف وما هي المقاييس المستخدمة. يساعد التمرين على فهم هذا الأمر بشكل أفضل ، ولكن هذا موضوع ضخم نعدك بكتابة منشور منفصل حوله وإنشاء طاولة مفتوحة حتى يتمكن الجميع من اللعب وفهم كيفية اختلاف ذلك عمليًا.
الأسرة "ولكن لنختار الأفضل" ستكون ROC AUC . هذا هو بالضبط ما نريده من المقياس في هذه الحالة: كلما كانت الإيجابيات أقل خطأ وكلما كان التنبؤ الفعلي أكثر دقة ، زاد ROC AUC.
لنموذج ROC المثالي ، AUC هو 1 ، لنموذج عشوائي مثالي يحدد الفئات بشكل عشوائي تمامًا - 0.5.
الخوارزميات
يجب أن يأخذ صندوقنا الأسود في الاعتبار توزيع أبطال الكتب ، ويأخذ اسمًا مختلفًا ولقبًا كإدخال ، ويعطي النتيجة. لحل مشكلة التصنيف ، يمكنك استخدام خوارزميات التعلم الآلي المختلفة:
الشبكات العصبية ، وآلات التجهيز ، والانحدار الخطي ، أو على سبيل المثال ، SVM.
على عكس الاعتقاد الشائع ، لا يقتصر علم البيانات على الشبكات العصبية فقط ، ولتعميم هذه الفكرة ، تُترك الشبكات العصبية في هذه المقالة بمثابة تمرين للقارئ الفضولي . أولئك الذين لم يلتحقوا بدورة واحدة في تحليل البيانات (خاصة تلك الأفضل ذاتيًا من ODS) ، أو ببساطة يقرأون أخبارًا عن التعلم الآلي أو الذكاء الاصطناعي ، والتي يتم نشرها الآن حتى في مجلات الصيادين الهواة ، يجب أن يكونوا قد التقوا بأسماء مجموعات عامة من الخوارزميات : التعبئة ، التعزيز ، طريقة متجه الدعم (SVM) ، الانحدار الخطي. هم الذين سنستخدمهم لحل مشكلتنا.
ولكي نكون أكثر دقة ، نقارن:
- الانحدار الخطي
- تعزيز (XGboost ، LightGBM)
- تحديد الأشجار (بالمعنى الدقيق للكلمة ، هذا هو نفس الدفعة ، لكننا سنخرجها بشكل منفصل: أشجار إضافية)
- التعبئة (غابة عشوائية)
- SVM
يمكننا حل مشكلة توزيع كل طالب من طلاب هوجورتس على إحدى الكليات من خلال تحديد أعضاء هيئة التدريس المناظرين له ، ولكن بشكل دقيق ، فإن هذه المهمة تأتي في حل مشكلة تحديد ما إذا كان كل فصل ينتمي بشكل فردي. لذلك ، في إطار هذه المقالة ، وضعنا لأنفسنا هدف الحصول على 4 نماذج ، نموذج لكل كلية.
البيانات
يعد العثور على مجموعة البيانات المناسبة للتدريب ، والأهم من ذلك ، قانونيًا لاستخدامها للغرض الصحيح ، أحد أكثر المهام تعقيدًا واستهلاكًا للوقت في علوم البيانات. لمهمتنا ، سنأخذ البيانات من ويكيا حول العالم لهاري بوتر. على سبيل المثال ، على هذا الرابط ، يمكنك العثور على جميع الشخصيات التي درست في كلية جريفندور. من المهم أن نستخدم في هذه الحالة البيانات لأغراض غير تجارية ، وبالتالي فإننا لا ننتهك ترخيص هذا الموقع.

بالنسبة لأولئك الذين يعتقدون أن علماء البيانات هم أشخاص رائعون ، سأذهب إلى علماء البيانات ودعوني أعلم ، نذكرك أن هناك خطوة مثل تنظيف البيانات وإعدادها. يجب أن يتم الإشراف على البيانات التي تم تنزيلها يدويًا من أجل حذف ، على سبيل المثال ، "المحافظ السابع لجريفندور" وحذف "فتاة غير معروفة من جريفندور" بشكل شبه تلقائي. في العمل الحقيقي ، يرتبط جزء كبير نسبيًا من المهمة دائمًا بإعداد القيم المفقودة وتنظيفها واستعادتها في مجموعة البيانات.
قليلا ctrl + c & ctrl + v وعند الإخراج نحصل على 4 ملفات نصية ، والتي تحتوي على أسماء الأحرف في لغتين: الإنجليزية والروسية.
نقوم بدراسة البيانات التي تم جمعها (EDA ، تحليل البيانات الاستكشافية)
في هذه المرحلة لدينا 4 ملفات تحتوي على أسماء طلاب الكليات وسنبحث بمزيد من التفصيل:
$ ls ../input griffindor.txt hufflpuff.txt ravenclaw.txt slitherin.txt
يحتوي كل ملف على اسم واحد ولقب (إن وجد) للطالب في كل سطر:
$ wc -l ../input/*.txt 250 ../input/griffindor.txt 167 ../input/hufflpuff.txt 180 ../input/ravenclaw.txt 254 ../input/slitherin.txt 851 total
البيانات التي تم جمعها هي:
$ cat ../input/griffindor.txt | head -3 && cat ../input/griffindor.txt | tail -3 Charlie Stainforth Melanie Stanmore Stewart
تستند فكرتنا بأكملها على افتراض وجود شيء مشابه في الأسماء والألقاب يمكن أن يتعلم الصندوق الأسود (أو القبعة السوداء) كيفية تمييزه.
يمكن للخوارزمية أن تغذي الخطوط كما هي ، لكن النتيجة لن تكون جيدة ، لأن النماذج الأساسية لن تكون قادرة على فهم كيفية اختلاف "دراكو" عن "هاري" بشكل مستقل ، لذا سنحتاج إلى استخراج الإشارات من أسمائنا وألقابنا.
إعداد البيانات (هندسة الميزات)
العلامات (أو الميزات ، من الميزة الإنجليزية - الخاصية) هي الخصائص المميزة للكائن. عدد المرات التي قام فيها شخص بتغيير وظائفه خلال العام الماضي ، وعدد الأصابع على يده اليسرى ، وسعة محرك المحرك ، سواء تجاوزت المسافة المقطوعة للسيارة 100000 كم أم لا. تم اختراع جميع أنواع تصنيفات اللافتات من قبل عدد كبير جدًا ، لا يوجد ولا يمكن أن يكون هناك نظام واحد في هذا الصدد ، لذلك سنقدم أمثلة على العلامات التي يمكن أن تكون:
- رقم منطقي
- الفئة (حتى 12 أو 12-18 أو 18+)
- قيمة ثنائية (أعاد القرض الأول أم لا)
- التاريخ واللون والأسهم وما إلى ذلك.
غالبًا ما يبرز البحث (أو تشكيل) الميزات (في هندسة الميزات الإنجليزية ) كمرحلة منفصلة من البحث أو عمل أخصائي تحليل البيانات. في الواقع ، يساعد الحس السليم والخبرة واختبار الفرضية في العملية نفسها. تخمين العلامات الصحيحة على الفور هو مزيج من اليد الكاملة والمعرفة الأساسية والحظ. في بعض الأحيان يوجد الشامانية فيه ، لكن النهج العام بسيط للغاية: تحتاج إلى القيام بما يتبادر إلى الذهن ، ثم التحقق مما إذا كان من الممكن تحسين الحل عن طريق إضافة سمة جديدة. على سبيل المثال ، كإشارة لمهمتنا ، يمكننا أن نأخذ عدد الأزيز في الاسم.
في الإصدار الأول (لأن دراسة علوم البيانات الحقيقية - كتحفة فنية ، لا يمكن إكمالها أبدًا) من نموذجنا ، سنستخدم الميزات التالية للاسم واللقب:
- 1 والحرف الأخير من الكلمة - حرف علة أو ساكن
- حروف العلة المزدوجة والحروف الساكنة
- عدد حروف العلة والحروف الساكنة والصم
- طول الاسم ، طول الاسم الأخير
- ...
للقيام بذلك ، سنأخذ هذا المستودع كأساس ونضيف فئة حتى يمكن استخدامه للحروف اللاتينية. سيعطينا هذا الفرصة لتحديد كيف يبدو كل حرف.
>> from Phonetic import RussianLetter, EnglishLetter >> RussianLetter('').classify() {'consonant': True, 'deaf': False, 'hard': False, 'mark': False, 'paired': False, 'shock': False, 'soft': False, 'sonorus': True, 'vowel': False} >> EnglishLetter('d').classify() {'consonant': True, 'deaf': False, 'hard': True, 'mark': False, 'paired': False, 'shock': False, 'soft': False, 'sonorus': True, 'vowel': False}
الآن يمكننا تحديد وظائف بسيطة لحساب الإحصائيات ، على سبيل المثال:
def starts_with_letter(word, letter_type='vowel'): """ , . :param word: :param letter_type: 'vowel' 'consonant'. . :return: Boolean """ if len(word) == 0: return False return Letter(word[0]).classify()[letter_type] def count_letter_type(word): """ . :param word: :param debug: :return: :obj:`dict` of :obj:`str` => :int:count """ count = { 'consonant': 0, 'deaf': 0, 'hard': 0, 'mark': 0, 'paired': 0, 'shock': 0, 'soft': 0, 'sonorus': 0, 'vowel': 0 } for letter in word: classes = Letter(letter).classify() for key in count.keys(): if classes[key]: count[key] += 1 return count
باستخدام هذه الوظائف ، يمكننا بالفعل الحصول على العلامات الأولى:
from feature_engineering import * >> print(" («»): ", len("")) («»): 5 >> print(" («») : ", starts_with_letter('', 'vowel')) («») : False >> print(" («») : ", starts_with_letter('', 'consonant')) («») : True >> count_Harry = count_letter_type("") >> print (" («»): ", count_Harry['paired']) («»): 1
بالمعنى الدقيق للكلمة ، بمساعدة هذه الوظائف ، يمكننا الحصول على تمثيل متجه للسلسلة ، أي نحصل على التعيين:
يمكننا الآن تقديم بياناتنا في شكل مجموعة بيانات يمكن إدخالها في خوارزمية التعلم الآلي:
>> from data_loaders import load_processed_data >> hogwarts_df = load_processed_data() >> hogwarts_df.head()

علاوة على ذلك ، ونتيجة لذلك ، نحصل على الأعراض التالية لكل طالب:
>> hogwarts_df[hogwarts_df.columns].dtypes
تلقت لافتات name object surname object is_english bool name_starts_with_vowel bool name_starts_with_consonant bool name_ends_with_vowel bool name_ends_with_consonant bool name_length int64 name_vowels_count int64 name_double_vowels_count int64 name_consonant_count int64 name_double_consonant_count int64 name_paired_count int64 name_deaf_count int64 name_sonorus_count int64 surname_starts_with_vowel bool surname_starts_with_consonant bool surname_ends_with_vowel bool surname_ends_with_consonant bool surname_length int64 surname_vowels_count int64 surname_double_vowels_count int64 surname_consonant_count int64 surname_double_consonant_count int64 surname_paired_count int64 surname_deaf_count int64 surname_sonorus_count int64 is_griffindor int64 is_hufflpuff int64 is_ravenclaw int64 is_slitherin int64 dtype: object
الأعمدة الأربعة الأخيرة مستهدفة - فهي تحتوي على معلومات عن الكلية التي يلتحق بها الطالب.
تدريب الخوارزميات
باختصار ، يتم تدريب الخوارزميات تمامًا مثل الأشخاص: فهم يرتكبون الأخطاء ويتعلمون منها. من أجل فهم مقدار الخطأ الذي ارتكبوه ، تستخدم الخوارزميات وظائف الخطأ (وظائف الخسارة ، وظيفة فقدان اللغة الإنجليزية ).
كقاعدة ، عملية التعلم بسيطة للغاية وتتكون من عدة خطوات:
- توقع.
- قيم الخطأ.
- تصحيح معلمات النموذج.
- كرر 1-3 حتى الوصول إلى الهدف ، تتوقف العملية أو تنتهي البيانات.
قيم جودة النموذج الناتج.
عمليًا ، بالطبع ، كل شيء أكثر تعقيدًا. على سبيل المثال ، هناك ظاهرة الإفراط في التجهيز - يمكن للخوارزمية أن تتذكر حرفياً الميزات التي تتوافق مع الإجابة وبالتالي تزيد من سوء النتيجة بالنسبة لأشياء لا تشبه تلك التي تم تدريبها عليها. لتجنب هذا ، هناك تقنيات واختراق مختلفة.
كما ذكرنا أعلاه ، سنقوم بحل 4 مشاكل: مشكلة لكل كلية. لذلك ، سنقوم بإعداد البيانات لسليذرين:
أثناء التعلم ، تقارن الخوارزمية باستمرار نتائجها بالبيانات الحقيقية ، لهذا الجزء من مجموعة البيانات مخصص للتحقق. يتم اعتبار قاعدة النغمة الجيدة أيضًا لتقييم نتيجة الخوارزمية على البيانات الفردية التي لم تراها الخوارزمية على الإطلاق. لذلك ، نقوم الآن بتقسيم العينة بنسبة 70/30 وتدريب الخوارزمية الأولى:
from sklearn.cross_validation import train_test_split from sklearn.ensemble import RandomForestClassifier
تم. الآن ، إذا قمت بإرسال بيانات لإدخال هذا النموذج ، فسيؤدي إلى نتيجة. هذا ممتع ، لذا سنتحقق أولاً من أن النموذج في Harry يتعرف على Slytherin. للقيام بذلك ، قم أولاً بإعداد الوظائف من أجل الحصول على تنبؤ الخوارزمية:
عرض الكود from data_loaders import parse_line_to_hogwarts_df import pandas as pd def get_single_student_features (name): """ :param name: string :return: pd.DataFrame """ featurized_person_df = parse_line_to_hogwarts_df(name) person_df = pd.DataFrame(featurized_person_df, columns=[ 'name', 'surname', 'is_english', 'name_starts_with_vowel', 'name_starts_with_consonant', 'name_ends_with_vowel', 'name_ends_with_consonant', 'name_length', 'name_vowels_count', 'name_double_vowels_count', 'name_consonant_count', 'name_double_consonant_count', 'name_paired_count', 'name_deaf_count', 'name_sonorus_count', 'surname_starts_with_vowel', 'surname_starts_with_consonant', 'surname_ends_with_vowel', 'surname_ends_with_consonant', 'surname_length', 'surname_vowels_count', 'surname_double_vowels_count', 'surname_consonant_count', 'surname_double_consonant_count', 'surname_paired_count', 'surname_deaf_count', 'surname_sonorus_count', ], index=[0] ) featurized_person = person_df.drop( ['name', 'surname'], axis = 1 ) return featurized_person def get_predictions_vector (model, person): """ :param model: :param person: string :return: list """ encoded_person = get_single_student_features(person) return model.predict_proba(encoded_person)[0]
لنقم الآن بتعيين مجموعة بيانات اختبار صغيرة للنظر في نتائج الخوارزمية.
def score_testing_dataset (model): """ . :param model: """ testing_dataset = [ " ", "Kirill Malev", " ", "Harry Potter", " ", " ","Severus Snape", " ", "Tom Riddle", " ", "Salazar Slytherin"] for name in testing_dataset: print ("{} — {}".format(name, get_predictions_vector(model, name)[1])) score_testing_dataset(rfc_model)
— 0.5 Kirill Malev — 0.5 — 0.0 Harry Potter — 0.0 — 0.75 — 0.9 Severus Snape — 0.5 — 0.2 Tom Riddle — 0.5 — 0.2 Salazar Slytherin — 0.3
كانت النتائج مشكوك فيها. حتى مؤسس الكلية لن يكون في الكلية ، وفقًا لهذا النموذج. لذلك ، تحتاج إلى تقييم الجودة الصارمة: انظر إلى المقاييس التي طلبناها في البداية:
from sklearn.metrics import accuracy_score, roc_auc_score, classification_report predictions = rfc_model.predict(X_test) print("Classification report: ") print(classification_report(y_test, predictions)) print("Accuracy for Random Forest Model: %.2f" % (accuracy_score(y_test, predictions) * 100)) print("ROC AUC from first Random Forest Model: %.2f" % (roc_auc_score(y_test, predictions)))
Classification report: precision recall f1-score support 0 0.66 0.88 0.75 168 1 0.38 0.15 0.21 89 avg / total 0.56 0.62 0.56 257 Accuracy for Random Forest Model: 62.26 ROC AUC from first Random Forest Model: 0.51
ليس من المستغرب أن النتائج كانت مشبوهة للغاية - يشير ROC AUC من حوالي 0.51 إلى أن النموذج يتنبأ بشكل أفضل قليلاً من رمي العملة.
اختبار النتائج. مقاييس الجودة
باستخدام مثال واحد أعلاه ، نظرنا في كيفية تدريب خوارزمية واحدة تدعم واجهات sklearn. يتم تدريب البقية بنفس الطريقة تمامًا ، لذلك يمكننا فقط تدريب جميع الخوارزميات واختيار أفضل واحد في كل حالة.

هذا ليس معقدًا ، فلكل خوارزمية نقوم بتدريب 1 باستخدام الإعدادات القياسية ، وكذلك تدريب مجموعة كاملة ، والفرز من خلال الخيارات المختلفة التي تؤثر على جودة الخوارزمية. تُسمى هذه المرحلة ضبط النموذج أو تحسين المعلمات الفائقة وجوهرها بسيط للغاية: يتم تحديد مجموعة الإعدادات التي تعطي أفضل نتيجة.
from model_training import train_classifiers from data_loaders import load_processed_data import warnings warnings.filterwarnings('ignore')
— 0.09437856871661066 Kirill Malev — 0.20820536334902712 — 0.07550095601699099 Harry Potter — 0.07683794773639624 — 0.9414529336862744 — 0.9293671807790949 Severus Snape — 0.6576783576162999 — 0.18577792617672767 Tom Riddle — 0.8351835484058869 — 0.25930925139546795 Salazar Slytherin — 0.24008788903854789
تبدو الأرقام في هذا الإصدار أفضل بشكل شخصي مما كانت عليه في الماضي ، ولكنها لا تزال غير جيدة بما يكفي لعامل الكمال الداخلي. لذلك ، سوف ننزل إلى مستوى أعمق ونعود إلى معنى المنتج لمهمتنا: نحن بحاجة إلى التنبؤ بأكثر أعضاء هيئة التدريس على الأرجح ، والتي سيتم تحديد البطل من خلال قبعة التوزيع. هذا يعني أنك بحاجة إلى تدريب نماذج لكل قسم.

>> from model_training import train_all_models
استنتاج طويل لنتائج ونتائج الانحدار متعدد الحدود SVM Default Report Accuracy for SVM Default: 73.93 ROC AUC for SVM Default: 0.53 Tuned SVM Report Accuracy for Tuned SVM: 72.37 ROC AUC for Tuned SVM: 0.50 KNN Default Report Accuracy for KNN Default: 70.04 ROC AUC for KNN Default: 0.58 Tuned KNN Report Accuracy for Tuned KNN: 69.65 ROC AUC for Tuned KNN: 0.58 XGBoost Default Report Accuracy for XGBoost Default: 70.43 ROC AUC for XGBoost Default: 0.54 Tuned XGBoost Report Accuracy for Tuned XGBoost: 68.09 ROC AUC for Tuned XGBoost: 0.56 Random Forest Default Report Accuracy for Random Forest Default: 73.93 ROC AUC for Random Forest Default: 0.62 Tuned Random Forest Report Accuracy for Tuned Random Forest: 74.32 ROC AUC for Tuned Random Forest: 0.54 Extra Trees Default Report Accuracy for Extra Trees Default: 69.26 ROC AUC for Extra Trees Default: 0.57 Tuned Extra Trees Report Accuracy for Tuned Extra Trees: 73.54 ROC AUC for Tuned Extra Trees: 0.55 LGBM Default Report Accuracy for LGBM Default: 70.82 ROC AUC for LGBM Default: 0.62 Tuned LGBM Report Accuracy for Tuned LGBM: 74.71 ROC AUC for Tuned LGBM: 0.53 RGF Default Report Accuracy for RGF Default: 70.43 ROC AUC for RGF Default: 0.58 Tuned RGF Report Accuracy for Tuned RGF: 71.60 ROC AUC for Tuned RGF: 0.60 FRGF Default Report Accuracy for FRGF Default: 68.87 ROC AUC for FRGF Default: 0.59 Tuned FRGF Report Accuracy for Tuned FRGF: 69.26 ROC AUC for Tuned FRGF: 0.59 SVM Default Report Accuracy for SVM Default: 70.43 ROC AUC for SVM Default: 0.50 Tuned SVM Report Accuracy for Tuned SVM: 71.60 ROC AUC for Tuned SVM: 0.50 KNN Default Report Accuracy for KNN Default: 63.04 ROC AUC for KNN Default: 0.49 Tuned KNN Report Accuracy for Tuned KNN: 65.76 ROC AUC for Tuned KNN: 0.50 XGBoost Default Report Accuracy for XGBoost Default: 69.65 ROC AUC for XGBoost Default: 0.54 Tuned XGBoost Report Accuracy for Tuned XGBoost: 68.09 ROC AUC for Tuned XGBoost: 0.50 Random Forest Default Report Accuracy for Random Forest Default: 66.15 ROC AUC for Random Forest Default: 0.51 Tuned Random Forest Report Accuracy for Tuned Random Forest: 70.43 ROC AUC for Tuned Random Forest: 0.50 Extra Trees Default Report Accuracy for Extra Trees Default: 64.20 ROC AUC for Extra Trees Default: 0.49 Tuned Extra Trees Report Accuracy for Tuned Extra Trees: 70.82 ROC AUC for Tuned Extra Trees: 0.51 LGBM Default Report Accuracy for LGBM Default: 67.70 ROC AUC for LGBM Default: 0.56 Tuned LGBM Report Accuracy for Tuned LGBM: 70.82 ROC AUC for Tuned LGBM: 0.50 RGF Default Report Accuracy for RGF Default: 66.54 ROC AUC for RGF Default: 0.52 Tuned RGF Report Accuracy for Tuned RGF: 65.76 ROC AUC for Tuned RGF: 0.53 FRGF Default Report Accuracy for FRGF Default: 65.76 ROC AUC for FRGF Default: 0.53 Tuned FRGF Report Accuracy for Tuned FRGF: 69.65 ROC AUC for Tuned FRGF: 0.52 SVM Default Report Accuracy for SVM Default: 74.32 ROC AUC for SVM Default: 0.50 Tuned SVM Report Accuracy for Tuned SVM: 74.71 ROC AUC for Tuned SVM: 0.51 KNN Default Report Accuracy for KNN Default: 69.26 ROC AUC for KNN Default: 0.48 Tuned KNN Report Accuracy for Tuned KNN: 73.15 ROC AUC for Tuned KNN: 0.49 XGBoost Default Report Accuracy for XGBoost Default: 72.76 ROC AUC for XGBoost Default: 0.49 Tuned XGBoost Report Accuracy for Tuned XGBoost: 74.32 ROC AUC for Tuned XGBoost: 0.50 Random Forest Default Report Accuracy for Random Forest Default: 73.93 ROC AUC for Random Forest Default: 0.52 Tuned Random Forest Report Accuracy for Tuned Random Forest: 74.32 ROC AUC for Tuned Random Forest: 0.50 Extra Trees Default Report Accuracy for Extra Trees Default: 73.93 ROC AUC for Extra Trees Default: 0.52 Tuned Extra Trees Report Accuracy for Tuned Extra Trees: 73.93 ROC AUC for Tuned Extra Trees: 0.50 LGBM Default Report Accuracy for LGBM Default: 73.54 ROC AUC for LGBM Default: 0.52 Tuned LGBM Report Accuracy for Tuned LGBM: 74.32 ROC AUC for Tuned LGBM: 0.50 RGF Default Report Accuracy for RGF Default: 73.54 ROC AUC for RGF Default: 0.51 Tuned RGF Report Accuracy for Tuned RGF: 73.93 ROC AUC for Tuned RGF: 0.50 FRGF Default Report Accuracy for FRGF Default: 73.93 ROC AUC for FRGF Default: 0.53 Tuned FRGF Report Accuracy for Tuned FRGF: 73.93 ROC AUC for Tuned FRGF: 0.50 SVM Default Report Accuracy for SVM Default: 80.54 ROC AUC for SVM Default: 0.50 Tuned SVM Report Accuracy for Tuned SVM: 80.93 ROC AUC for Tuned SVM: 0.52 KNN Default Report Accuracy for KNN Default: 78.60 ROC AUC for KNN Default: 0.50 Tuned KNN Report Accuracy for Tuned KNN: 80.16 ROC AUC for Tuned KNN: 0.51 XGBoost Default Report Accuracy for XGBoost Default: 80.54 ROC AUC for XGBoost Default: 0.50 Tuned XGBoost Report Accuracy for Tuned XGBoost: 77.04 ROC AUC for Tuned XGBoost: 0.52 Random Forest Default Report Accuracy for Random Forest Default: 77.43 ROC AUC for Random Forest Default: 0.49 Tuned Random Forest Report Accuracy for Tuned Random Forest: 80.54 ROC AUC for Tuned Random Forest: 0.50 Extra Trees Default Report Accuracy for Extra Trees Default: 76.26 ROC AUC for Extra Trees Default: 0.48 Tuned Extra Trees Report Accuracy for Tuned Extra Trees: 78.60 ROC AUC for Tuned Extra Trees: 0.50 LGBM Default Report Accuracy for LGBM Default: 75.49 ROC AUC for LGBM Default: 0.51 Tuned LGBM Report Accuracy for Tuned LGBM: 80.54 ROC AUC for Tuned LGBM: 0.50 RGF Default Report Accuracy for RGF Default: 78.99 ROC AUC for RGF Default: 0.52 Tuned RGF Report Accuracy for Tuned RGF: 75.88 ROC AUC for Tuned RGF: 0.55 FRGF Default Report Accuracy for FRGF Default: 76.65 ROC AUC for FRGF Default: 0.50 # ,
from sklearn.linear_model import LogisticRegression clf = LogisticRegression(random_state=0, solver='lbfgs', multi_class='multinomial') hogwarts_df = load_processed_data_multi()
— [0.3602361 0.16166944 0.16771712 0.31037733] Kirill Malev — [0.47473072 0.16051924 0.13511385 0.22963619] — [0.38697926 0.19330242 0.17451052 0.2452078 ] Harry Potter — [0.40245098 0.16410043 0.16023278 0.27321581] — [0.13197025 0.16438855 0.17739254 0.52624866] — [0.17170203 0.1205678 0.14341742 0.56431275] Severus Snape — [0.15558044 0.21589378 0.17370406 0.45482172] — [0.39301231 0.07397324 0.1212741 0.41174035] Tom Riddle — [0.26623969 0.14194379 0.1728505 0.41896601] — [0.24843037 0.21632736 0.21532696 0.3199153 ] Salazar Slytherin — [0.09359144 0.26735897 0.2742305 0.36481909]
confusion_matrix:
confusion_matrix(clf.predict(X_data), y)
array([[144, 68, 64, 78], [ 8, 9, 8, 6], [ 22, 18, 31, 20], [ 77, 73, 78, 151]])
def get_predctions_vector (models, person): predictions = [get_predictions_vector (model, person)[1] for model in models] return { 'slitherin': predictions[0], 'griffindor': predictions[1], 'ravenclaw': predictions[2], 'hufflpuff': predictions[3] } def score_testing_dataset (models): testing_dataset = [ " ", "Kirill Malev", " ", "Harry Potter", " ", " ","Severus Snape", " ", "Tom Riddle", " ", "Salazar Slytherin"] data = [] for name in testing_dataset: predictions = get_predctions_vector(models, name) predictions['name'] = name data.append(predictions) scoring_df = pd.DataFrame(data, columns=['name', 'slitherin', 'griffindor', 'hufflpuff', 'ravenclaw']) return scoring_df
name slitherin griffindor hufflpuff ravenclaw 0 0.349084 0.266909 0.110311 0.091045 1 Kirill Malev 0.289914 0.376122 0.384986 0.103056 2 0.338258 0.400841 0.016668 0.124825 3 Harry Potter 0.245377 0.357934 0.026287 0.154592 4 0.917423 0.126997 0.176640 0.096570 5 0.969693 0.106384 0.150146 0.082195 6 Severus Snape 0.663732 0.259189 0.290252 0.074148 7 0.268466 0.579401 0.007900 0.083195 8 Tom Riddle 0.639731 0.541184 0.084395 0.156245 9 0.653595 0.147506 0.172940 0.137134 10 Salazar Slytherin 0.647399 0.169964 0.095450 0.26126

, . ROC AUC , 0.5. , :
, , , , XGBoost CV , .
! , 70% . , 4 .
from model_training import train_production_models from xgboost import XGBClassifier best_models = [] for i in range (0,4): best_models.append(XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1, colsample_bytree=0.7, gamma=0, learning_rate=0.05, max_delta_step=0, max_depth=6, min_child_weight=11, missing=-999, n_estimators=1000, n_jobs=1, nthread=4, objective='binary:logistic', random_state=0, reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=1337, silent=1, subsample=0.8)) slitherin_model, griffindor_model, ravenclaw_model, hufflpuff_model = \ train_production_models(best_models) top_models = slitherin_model, griffindor_model, ravenclaw_model, hufflpuff_model score_testing_dataset(top_models)
name slitherin griffindor hufflpuff ravenclaw 0 0.273713 0.372337 0.065923 0.279577 1 Kirill Malev 0.401603 0.761467 0.111068 0.023902 2 0.031540 0.616535 0.196342 0.217829 3 Harry Potter 0.183760 0.422733 0.119393 0.173184 4 0.945895 0.021788 0.209820 0.019449 5 0.950932 0.088979 0.084131 0.012575 6 Severus Snape 0.634035 0.088230 0.249871 0.036682 7 0.426440 0.431351 0.028444 0.083636 8 Tom Riddle 0.816804 0.136530 0.069564 0.035500 9 0.409634 0.213925 0.028631 0.252723 10 Salazar Slytherin 0.824590 0.067910 0.111147 0.085710
, , .
, , . .
import pickle pickle.dump(slitherin_model, open("../output/slitherin.xgbm", "wb")) pickle.dump(griffindor_model, open("../output/griffindor.xgbm", "wb")) pickle.dump(ravenclaw_model, open("../output/ravenclaw.xgbm", "wb")) pickle.dump(hufflpuff_model, open("../output/hufflpuff.xgbm", "wb"))
, . , , , .
, , . , . , Data Scientist — -.
:
, docker-, python-. , flask.
from __future__ import print_function
Dockerfile:
FROM datmo/python-base:cpu-py35
:
docker build -t talking_hat . && docker rm talking_hat && docker run --name talking_hat -p 5000:5000 talking_hat
— . , Apache Benchmark . , . — .
$ ab -p data.json -T application/json -c 50 -n 10000 http://0.0.0.0:5000/predict
ab This is ApacheBench, Version 2.3 <$Revision: 1807734 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 0.0.0.0 (be patient) Completed 1000 requests Completed 2000 requests Completed 3000 requests Completed 4000 requests Completed 5000 requests Completed 6000 requests Completed 7000 requests Completed 8000 requests Completed 9000 requests Completed 10000 requests Finished 10000 requests Server Software: Werkzeug/0.14.1 Server Hostname: 0.0.0.0 Server Port: 5000 Document Path: /predict Document Length: 141 bytes Concurrency Level: 50 Time taken for tests: 238.552 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 2880000 bytes Total body sent: 1800000 HTML transferred: 1410000 bytes Requests per second: 41.92 [#/sec] (mean) Time per request: 1192.758 [ms] (mean) Time per request: 23.855 [ms] (mean, across all concurrent requests) Transfer rate: 11.79 [Kbytes/sec] received 7.37 kb/s sent 19.16 kb/s total Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.1 0 3 Processing: 199 1191 352.5 1128 3352 Waiting: 198 1190 352.5 1127 3351 Total: 202 1191 352.5 1128 3352 Percentage of the requests served within a certain time (ms) 50% 1128 66% 1277 75% 1378 80% 1451 90% 1668 95% 1860 98% 2096 99% 2260 100% 3352 (longest request)
, :
def prod_predict_classes_for_name (full_name): <...> predictions = get_predctions_vector([ app.slitherin_model, app.griffindor_model, app.ravenclaw_model, app.hufflpuff_model ], person_df.drop(['name', 'surname'], axis=1)) return { 'slitherin': float(predictions[0][1]), 'griffindor': float(predictions[1][1]), 'ravenclaw': float(predictions[2][1]), 'hufflpuff': float(predictions[3][1]) } def create_app(): <...> with app.app_context(): app.slitherin_model = pickle.load(open("models/slitherin.xgbm", "rb")) app.griffindor_model = pickle.load(open("models/griffindor.xgbm", "rb")) app.ravenclaw_model = pickle.load(open("models/ravenclaw.xgbm", "rb")) app.hufflpuff_model = pickle.load(open("models/hufflpuff.xgbm", "rb")) return app
:
$ docker build -t talking_hat . && docker rm talking_hat && docker run --name talking_hat -p 5000:5000 talking_hat $ ab -p data.json -T application/json -c 50 -n 10000 http://0.0.0.0:5000/predict
ab This is ApacheBench, Version 2.3 <$Revision: 1807734 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 0.0.0.0 (be patient) Completed 1000 requests Completed 2000 requests Completed 3000 requests Completed 4000 requests Completed 5000 requests Completed 6000 requests Completed 7000 requests Completed 8000 requests Completed 9000 requests Completed 10000 requests Finished 10000 requests Server Software: Werkzeug/0.14.1 Server Hostname: 0.0.0.0 Server Port: 5000 Document Path: /predict Document Length: 141 bytes Concurrency Level: 50 Time taken for tests: 219.812 seconds Complete requests: 10000 Failed requests: 3 (Connect: 0, Receive: 0, Length: 3, Exceptions: 0) Total transferred: 2879997 bytes Total body sent: 1800000 HTML transferred: 1409997 bytes Requests per second: 45.49 [#/sec] (mean) Time per request: 1099.062 [ms] (mean) Time per request: 21.981 [ms] (mean, across all concurrent requests) Transfer rate: 12.79 [Kbytes/sec] received 8.00 kb/s sent 20.79 kb/s total Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.1 0 2 Processing: 235 1098 335.2 1035 3464 Waiting: 235 1097 335.2 1034 3462 Total: 238 1098 335.2 1035 3464 Percentage of the requests served within a certain time (ms) 50% 1035 66% 1176 75% 1278 80% 1349 90% 1541 95% 1736 98% 1967 99% 2141 100% 3464 (longest request)
. . , .
الخلاصة
, . - .
, :
- feature engineering- ( ), , Soundex .
- PyTorch . , , .
- flask Quart , , .
- - -, .
, , . , !
لم يكن من الممكن نشر هذه المقالة بدون مجتمع Open Data Science ، الذي يجمع عددًا كبيرًا من الخبراء الناطقين بالروسية في مجال تحليل البيانات.