"الطريق الطويل في انتظارك ..." أو حل مشكلة التنبؤ في C # باستخدام Ml.NET (DataScience)

في الآونة الأخيرة ، صادفت المزيد والمزيد من المعلومات حول إطار التعلم الآلي Ml.NET . نما عدد الإشارات إلى الجودة ، وقررت أن أنظر على الأقل بنظرة واحدة في لمحة عن نوع الحيوان الذي كانت عليه.

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

بعد بضع سنوات على مجموعة بيانات محدثة ، سنحاول حل المشكلة البسيطة . باستخدام نموذج الانحدار في Ml.NET Framework ، نتوقع عدد الطلبات في الشهر التي تحصل على حل إيجابي. على طول الطريق ، سنقارن Ml.NET مع أكورد. مكتبات NET و Python.

هل تريد السيطرة على قوة وقوة المتنبئ؟ ثم اهلا وسهلا بكم تحت القط.



ملاحظة: اسمحوا S.S. سوبيانين ، لن يقول المقال كلمة عن السياسة.


المحتويات:

الجزء الأول: مقدمة وقليلا عن البيانات
الجزء الثاني: كتابة رمز C #
الجزء الثالث: الخاتمة

أعتقد أنه من الضروري أن نحذرك فورًا من أنني لست مؤيدًا في تحليل البيانات والبرمجة بشكل عام ، ولا أتعامل مع مجلس مدينة موسكو. لذلك ، من المحتمل أن يكون المقال من مبتدئ إلى مبتدئ. لكن على الرغم من معرفتي المحدودة ، آمل أن تكون المقالة مفيدة لك.

قد يتذكر الأشخاص الذين هم على دراية بالفعل بالمقالات السابقة من الدورة أننا حاولنا بالفعل حل مشكلة التنبؤ بعدد القضايا التي تم حلها بشكل إيجابي من نداءات المواطنين الموجهة إلى الفرع التنفيذي لموسكو. لهذا ، استخدمنا إطار عمل Python و Accord.Net .

مقالات دورة أخرى


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

تتوفر جميع مواد المقالة ، بما في ذلك الكود ومجموعة البيانات ، مجانًا على GitHub .

يتم تقديم البيانات على GitHub بتنسيق CSV ، وتحتوي على 44 إدخالًا ، ومن حيث المبدأ ، يمكن (ويجب) استخدامها ليس فقط لتحليل المثال.

تعني أعمدة البيانات ما يلي:

  • الرقم القياسي سجل
  • سنة - سنة قياسية
  • شهر - شهر من التسجيل
  • total_appeals - إجمالي عدد مرات الدخول شهريًا
  • appeals_to_mayor - إجمالي عدد الطعون المقدمة إلى العمدة
  • res_positive- عدد القرارات الإيجابية
  • res_explained - عدد المكالمات للتوضيح
  • res_negative - عدد المكالمات بقرار سلبي
  • El_form_to_mayor - عدد الطعون المقدمة إلى العمدة في شكل إلكتروني
  • Pap_form_to_mayor - عدد الطعون المقدمة إلى العمدة على الورق to_10K_total_VAO ... to_10K_total_YUZAO - عدد الطعون لكل 10000 من السكان في مناطق مختلفة من موسكو
  • to_10K_mayor_VAO ... to_10K_mayor_YUZAO - عدد الطعون الموجهة إلى العمدة وحكومة موسكو لكل 10000 من السكان في مناطق مختلفة من المدينة

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

حاليًا ، يتم تقديم البيانات الموجودة على موقع الحكومة في موسكو بالكامل من يناير 2016 إلى أغسطس 2019 (بعض البيانات مفقودة في سبتمبر). وبالتالي ، سيكون لدينا 44 الإدخالات. قليلا ، بالطبع ، ولكن للتظاهر لنا هذا سيكون كافيا.

قبل أن تبدأ ، مجرد بضع كلمات عن بطل مقالتنا.
ML.NET Framework - تطوير المصادر المفتوحة من Microsoft. وفقًا لإعلانات وسائل التواصل الاجتماعي ، هذا هو ردهم على مكتبات Python للتعلم الآلي إطار العمل متعدد المنصات ويسمح لك بحل مجموعة واسعة من المهام من الانحدار البسيط والتصنيف إلى التعلم العميق. على الرفاق هبر نفذت بالفعل تحليل ML.NET والمكتبات في بيثون. من يهتم ، وهنا هو الرابط .

لن أقدم دليلاً مفصلاً لتثبيت Ml.NET واستخدامه لأنه ، في جوهره ، تم فصل كل شيء عن "تكييف" بناءً على كتاب مدرسي من موقع Microsoft الرسمي . هناك ، تم حل مشكلة أسعار رحلة في سيارة أجرة ، ولكي نكون صادقين ، هناك المزيد من الفوائد منها

لكنني أعتقد أن التفسيرات الصغيرة لن تكون ضرورية.

لقد استخدمت Visual Studio 2017 مع آخر التحديثات.
اعتمد المشروع على قالب تطبيق وحدة التحكم .NET Core (الإصدار 2.1).
كان على المشروع تثبيت حزم NuGet Microsoft.ML و Microsoft.ML.FastTree. هذا ، في الواقع ، هو الإعداد كله.


ننتقل مباشرة إلى الرمز.

أولاً ، قمت بإنشاء فئة MayorAppel ، التي وصفتها بترتيب الأعمدة التي تحتوي على بيانات من ملفات CSV.
كيف لا يصعب تخمين [LoadColumn (0)]
- يخبرنا ما هو العمود من ملف CSV الذي نتخذه.
بعد ذلك ، بعد البرنامج التعليمي ، قمت بإنشاء فئة MayorAppelPrediction - للحصول على نتائج التنبؤ

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

رمز الفئة لوصف البيانات
using Microsoft.ML.Data; namespace app_to_mayor_mlnet { class MayorAppel { [LoadColumn(0)] public float Year; [LoadColumn(1)] public string Month; [LoadColumn(2)] public float TotalAppeals; [LoadColumn(3)] public float AppealsToMayor; [LoadColumn(4)] public float ResPositive; [LoadColumn(5)] public float ResExplained; [LoadColumn(6)] public float ResNegative; [LoadColumn(7)] public float ElFormToMayor; [LoadColumn(8)] public float PapFormToMayor; [LoadColumn(9)] public float To10KTotalVAO; [LoadColumn(10)] public float To10KMayorVAO; [LoadColumn(11)] public float To10KTotalZAO; [LoadColumn(12)] public float To10KMayorZAO; [LoadColumn(13)] public float To10KTotalZelAO; [LoadColumn(14)] public float To10KMayorZelAO; [LoadColumn(6)] public float To10KTotalSAO; [LoadColumn(15)] public float To10KMayorSAO; [LoadColumn(16)] public float To10KTotalSVAO; [LoadColumn(17)] public float To10KMayorSVAO; [LoadColumn(18)] public float To10KTotalSZAO; [LoadColumn(19)] public float To10KMayorSZAO; [LoadColumn(20)] public float To10KTotalTiNAO; [LoadColumn(21)] public float To10KMayorTiNAO; [LoadColumn(22)] public float To10KTotalCAO; [LoadColumn(23)] public float To10KMayorCAO; [LoadColumn(24)] public float To10KTotalYUAO; [LoadColumn(25)] public float To10KMayorYUAO; [LoadColumn(26)] public float To10KTotalYUVAO; [LoadColumn(27)] public float To10KMayorYUVAO; [LoadColumn(28)] public float To10KTotalYUZAO; [LoadColumn(29)] public float To10KMayorYUZAO; } public class MayorAppelPrediction { [ColumnName("Score")] public float ResPositive; } } 


دعنا ننتقل إلى رمز البرنامج الرئيسي.
لا تنس أن تضيف في البداية:

 using System.IO; using Microsoft.ML; 


فيما يلي وصف لحقول البيانات.

 namespace app_to_mayor_mlnet { class Program { static readonly string _trainDataPath = Path.Combine(Environment.CurrentDirectory, "Data", "train_data.csv"); static readonly string _testDataPath = Path.Combine(Environment.CurrentDirectory, "Data", "test_data.csv"); static readonly string _modelPath = Path.Combine(Environment.CurrentDirectory, "Data", "Model.zip"); 


في هذه الحقول ، في الواقع ، يتم تخزين المسارات إلى ملفات البيانات ، قررت هذه المرة فصلها مسبقًا (على عكس الحالة في Accord.NET)

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

بعد ذلك ، يأتي التحدي المتمثل في الأساليب التي تشكل النموذج ، وإجراء تقييمه وتعطينا تنبؤًا.

  static void Main(string[] args) { MLContext mlContext = new MLContext(seed: 0); var model = Train(mlContext, _trainDataPath); Evaluate(mlContext, model); TestSinglePrediction(mlContext, model); } 


دعنا نذهب في النظام

هناك حاجة إلى طريقة القطار لتدريب النموذج.

 public static ITransformer Train(MLContext mlContext, string dataPath) { IDataView dataView = mlContext.Data.LoadFromTextFile<MayorAppel>(dataPath, hasHeader: true, separatorChar: ','); var pipeline = mlContext.Transforms.CopyColumns(outputColumnName: "Label", inputColumnName: "ResPositive") .Append(mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "MonthEncoded", inputColumnName: "Month")) .Append(mlContext.Transforms.Concatenate("Features", "Year", "MonthEncoded", "TotalAppeals", "AppealsToMayor", "ResExplained", "ResNegative", "ElFormToMayor", "PapFormToMayor", "To10KTotalVAO", "To10KMayorVAO", "To10KTotalZAO", "To10KMayorZAO", "To10KTotalZelAO", "To10KMayorZelAO", "To10KTotalSAO", "To10KMayorSAO" , "To10KTotalSVAO", "To10KMayorSVAO", "To10KTotalSZAO", "To10KMayorSZAO", "To10KTotalTiNAO", "To10KMayorTiNAO" , "To10KTotalCAO", "To10KMayorCAO", "To10KTotalYUAO", "To10KMayorYUAO", "To10KTotalYUVAO", "To10KMayorYUVAO" , "To10KTotalYUZAO", "To10KMayorYUZAO")).Append(mlContext.Regression.Trainers.FastTree()); var model = pipeline.Fit(dataView); return model; } 


في البداية نقرأ البيانات من عينة التدريب. ثم في السلسلة نحدد المعلمة التي ستتنبأ (التسمية).

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

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

في الختام ، نحن نشكل ونعيد النموذج النهائي.

بعد ذلك ، نقوم بتقييم جودة التنبؤ من خلال نموذجنا.

  private static void Evaluate(MLContext mlContext, ITransformer model) { IDataView dataView = mlContext.Data.LoadFromTextFile<MayorAppel>(_testDataPath, hasHeader: true, separatorChar: ','); var predictions = model.Transform(dataView); var metrics = mlContext.Regression.Evaluate(predictions, "Label", "Score"); Console.WriteLine(); Console.WriteLine($"*************************************************"); Console.WriteLine($"* Model quality metrics evaluation "); Console.WriteLine($"*------------------------------------------------"); Console.WriteLine($"* RSquared Score: {metrics.RSquared:0.##}"); Console.WriteLine($"* Root Mean Squared Error: {metrics.RootMeanSquaredError:#.##}"); } 

نقوم بتحميل عينة الاختبار (الأشهر الأربعة الأخيرة من المجموعة) ، نحصل على التنبؤ ببيانات الاختبار الخاصة بنا على النموذج المدرب باستخدام طريقة Transform (). ثم نقوم بحساب المقاييس وطباعتها. في هذه الحالة ، هو معامل التصميم والانحراف المعياري. يجب أن تميل الأولى إلى 1 ، والثانية أساسًا إلى الصفر.

من حيث المبدأ ، من أجل تقديم تنبؤ ، لم نكن بحاجة إلى هذه الطريقة ، لكن من الجيد أن نفهم إلى أي مدى يتنبأ نموذجنا بشيء ما.

تبقى الطريقة الأخيرة - التنبؤ نفسه.
سنقوم بإخفائه أيضًا تحت المفسد.

طريقة التنبؤ والبيانات
 private static void TestSinglePrediction(MLContext mlContext, ITransformer model) { var predictionFunction = mlContext.Model.CreatePredictionEngine<MayorAppel, MayorAppelPrediction>(model); var MayorAppelSampleMinData = new MayorAppel() { Year = 2019, Month = "August", ResPositive = 0 }; var MayorAppelSampleMediumData = new MayorAppel() { Year = 2019, Month = "August", TotalAppeals = 111340, AppealsToMayor = 17932, ResExplained = 66858, ResNegative = 8945, ElFormToMayor = 14931, PapFormToMayor = 2967, ResPositive = 0 }; var MayorAppelSampleMaxData = new MayorAppel() { Year = 2019, Month = "August", TotalAppeals = 111340, AppealsToMayor = 17932, ResExplained = 66858, ResNegative = 8945, ElFormToMayor = 14931, PapFormToMayor = 2967, To10KTotalVAO = 67, To10KMayorVAO = 13, To10KTotalZAO = 57, To10KMayorZAO = 13, To10KTotalZelAO = 49, To10KMayorZelAO = 9, To10KTotalSAO = 71, To10KMayorSAO = 14, To10KTotalSVAO = 86, To10KMayorSVAO = 27, To10KTotalSZAO = 68, To10KMayorSZAO = 12, To10KTotalTiNAO = 93, To10KMayorTiNAO = 36, To10KTotalCAO = 104, To10KMayorCAO = 24, To10KTotalYUAO = 56, To10KMayorYUAO = 12, To10KTotalYUVAO = 59, To10KMayorYUVAO = 13, To10KTotalYUZAO = 78, To10KMayorYUZAO = 23, ResPositive = 0 }; var predictionMin = predictionFunction.Predict(MayorAppelSampleMinData); var predictionMed = predictionFunction.Predict(MayorAppelSampleMediumData); var predictionMax = predictionFunction.Predict(MayorAppelSampleMaxData); Console.WriteLine($"**********************************************************************"); Console.WriteLine($"Prediction for August 2019"); Console.WriteLine($"Predicted Positive decisions (Minimum Features): {predictionMin.ResPositive:0.####}, actual res_positive : 22313"); Console.WriteLine($"Predicted Positive decisions (Medium Features: {predictionMed.ResPositive:0.####}, actual res_positive : 22313"); Console.WriteLine($"Predicted Positive decisions (Maximum Features): {predictionMax.ResPositive:0.####}, actual res_positive : 22313"); Console.WriteLine($"**********************************************************************"); } 



في المثال ، استخدمنا فئة PredictionEngine ، والتي تتيح لنا الحصول على تنبؤ واحد بناءً على النموذج المدرَّب ومجموعة بيانات الاختبار.

سنقوم بإنشاء ثلاثة "تحقيقات" مع بيانات للتنبؤ.
الأول مع مجموعة الحد الأدنى من البيانات (شهر وسنة فقط) ، والثاني بمتوسط ​​والثالث مع مجموعة كاملة من السمات - على التوالي.

نحصل على ثلاثة تنبؤات مختلفة وطباعتها.

كما ترى في لقطة الشاشة (Windows 10 x64) ، فإن إضافة بيانات حول عدد المكالمات لكل 10000 من سكان المناطق ، في هذه الحالة ، يفسد كل شيء فقط ، لكن إضافة بقية البيانات تعطي زيادة طفيفة في دقة التنبؤ.



تحت Linux ، يجمع Mint 19 أيضًا بشكل رائع في Mono.
اتضح أن الإطار هو تماما عبر منصة.




في الختام ، كما وعدت ، سأقدم القليل من التحليل المقارن الذاتي لـ ML.NET مع مكتبات Accord.NET و Python للتعلم الآلي.

1. هناك شعور بأن المطورين يحاولون الامتثال للاتجاهات في مجال التعلم الآلي. بالطبع ، في Python مع مجموعة من المكتبات المثبتة في Anaconda ، يمكن حل هذه المهمة بشكل أكثر إحكاما وقضاء وقت أقل في التطوير. ولكن بشكل عام ، يبدو لي أن النهج المتبع في حل المشكلات مع ML.NET سهل للأشخاص الذين اعتادوا على حل مشكلات التعلم الآلي باستخدام Python.

2. مقارنةً بإطار Accord.NET Framework ، يبدو ML.NET أكثر ملاءمة واعدة للشخص الذي جرب التعلم الآلي في Python. أتذكر عندما حاولت كتابة شيء ما على Accord.NET قبل عامين ، كنت أفتقر بشكل رهيب إلى توضيحات وأمثلة لبعض الفصول والأساليب. في هذا الصدد ، تعمل Ml.NET مع الوثائق بشكل أفضل قليلاً ، على الرغم من أن الإطار أصغر بكثير من Accord.NET. عامل مهم آخر هو أن ML.NET ، بناءً على النشاط على GitHub ، يتطور بشكل مكثف أكثر من Accord.NET ولديه المزيد من المواد التدريبية باللغة الروسية.

نتيجة لذلك ، يبدو ML.NET للوهلة الأولى أداة مناسبة تكمل ترسانتك إذا لم تتمكن من استخدام Python أو R (على سبيل المثال ، عند العمل مع CAD APIs المنفذة على .NET).
أتمنى لك أسبوع عمل جيد!

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


All Articles