استكشاف خوارزميات التعلم الآلي الخاضعة للإشراف
نشرت: 2022-03-11الهدف الرئيسي من هذه القراءة هو فهم المنهجية الإحصائية الكافية لتكون قادرة على الاستفادة من خوارزميات التعلم الآلي في مكتبة بايثون scikit-Learn ثم تطبيق هذه المعرفة لحل مشكلة التعلم الآلي الكلاسيكية.
ستأخذنا المحطة الأولى في رحلتنا عبر تاريخ موجز للتعلم الآلي. ثم سنغوص في خوارزميات مختلفة. في محطتنا الأخيرة ، سوف نستخدم ما تعلمناه لحل مشكلة توقع معدل بقاء تيتانيك.
بعض إخلاء المسؤولية:
- أنا مهندس برمجيات متكامل ، ولست خبيرًا في خوارزمية التعلم الآلي.
- أفترض أنك تعرف بعض أساسيات بايثون.
- هذا استكشافي ، لذا لا يتم شرح كل التفاصيل كما لو كانت في برنامج تعليمي.
مع ذلك ، دعنا نتعمق!
مقدمة سريعة لخوارزميات التعلم الآلي
بمجرد مغامرتك في هذا المجال ، ستدرك أن التعلم الآلي أقل رومانسية مما قد تعتقد. في البداية ، كنت مليئًا بالآمال أنه بعد أن تعلمت المزيد ، سأتمكن من إنشاء جارفيس AI الخاص بي ، والذي سيقضي كل يوم في برمجة البرامج وكسب المال من أجلي ، حتى أتمكن من قضاء أيام كاملة في الهواء الطلق في قراءة الكتب ، وقيادة دراجة نارية ، وأتمتع بنمط حياة متهور بينما يجعل جارفيس الخاص بي جيوب أعمق. ومع ذلك ، سرعان ما أدركت أن أساس خوارزميات التعلم الآلي هو الإحصائيات ، والتي أجدها شخصياً مملة وغير مثيرة للاهتمام. لحسن الحظ ، اتضح أن الإحصاءات "الباهتة" لها بعض التطبيقات الرائعة للغاية.
ستكتشف قريبًا أنه للوصول إلى تلك التطبيقات الرائعة ، عليك أن تفهم الإحصائيات جيدًا. أحد أهداف خوارزميات التعلم الآلي هو إيجاد التبعيات الإحصائية في البيانات المقدمة.
يمكن أن تكون البيانات المقدمة أي شيء من فحص ضغط الدم مقابل العمر إلى العثور على نص مكتوب بخط اليد بناءً على لون وحدات البكسل المختلفة.
ومع ذلك ، كنت أشعر بالفضول لمعرفة ما إذا كان بإمكاني استخدام خوارزميات التعلم الآلي للعثور على التبعيات في وظائف تجزئة التشفير (SHA ، MD5 ، وما إلى ذلك) - ومع ذلك ، لا يمكنك فعل ذلك حقًا لأن أساسيات التشفير المناسبة يتم إنشاؤها بهذه الطريقة أنها تقضي على التبعيات وتنتج مخرجات يصعب التنبؤ بها بشكل كبير. أعتقد أنه بالنظر إلى مقدار الوقت غير المحدود ، يمكن لخوارزميات التعلم الآلي كسر أي نموذج تشفير.
لسوء الحظ ، ليس لدينا الكثير من الوقت ، لذلك نحن بحاجة إلى إيجاد طريقة أخرى لتعدين العملة المشفرة بكفاءة. إلى أي مدى وصلنا حتى الآن؟
تاريخ موجز لخوارزميات التعلم الآلي
تعود جذور خوارزميات التعلم الآلي إلى توماس بايز ، وهو إحصائي إنجليزي عاش في القرن الثامن عشر. وتدعم مقالته "مقال نحو حل مشكلة في عقيدة الفرص " نظرية بايز ، والتي يتم تطبيقها على نطاق واسع في مجال الإحصاء.
في القرن التاسع عشر ، نشر بيير سيمون لابلاس Theorie analytique des probabilites ، موسعًا عمل بايز وحدد ما نعرفه اليوم باسم نظرية بايز. قبل ذلك بوقت قصير ، وصف Adrien-Marie Legendre طريقة "المربعات الصغرى" ، والتي تُستخدم أيضًا على نطاق واسع اليوم في التعلم الخاضع للإشراف.
القرن العشرين هو الفترة التي تمت فيها غالبية الاكتشافات المعروفة للجمهور في هذا المجال. اخترع أندريه ماركوف سلاسل ماركوف التي استخدمها لتحليل القصائد. اقترح آلان تورينج آلة تعلم يمكن أن تصبح ذكاء اصطناعيًا ، وتنذر أساسًا بالخوارزميات الجينية. اخترع فرانك روزنبلات Perceptron ، مما أثار حماسة كبيرة وتغطية كبيرة في وسائل الإعلام.
ولكن بعد ذلك ، شهدت السبعينيات الكثير من التشاؤم حول فكرة الذكاء الاصطناعي - وبالتالي انخفاض التمويل - لذلك تسمى هذه الفترة بشتاء الذكاء الاصطناعي . تسببت إعادة اكتشاف التكاثر العكسي في الثمانينيات في عودة ظهور أبحاث التعلم الآلي. واليوم ، أصبح موضوعًا ساخنًا مرة أخرى.
ميز الراحل ليو بريمان بين نموذجين للنمذجة الإحصائية: نمذجة البيانات والنمذجة الحسابية. "النمذجة الحسابية" تعني إلى حد ما خوارزميات التعلم الآلي مثل الغابة العشوائية .
التعلم الآلي والإحصاء من المجالات وثيقة الصلة. وفقًا لمايكل جوردان ، فإن أفكار التعلم الآلي ، من المبادئ المنهجية إلى الأدوات النظرية ، لها تاريخ طويل في الإحصاء. كما اقترح أيضًا علم البيانات كمصطلح نائب للمشكلة الشاملة التي يعمل عليها اختصاصيو التعلم الآلي والإحصائيون ضمنيًا.
فئات خوارزميات التعلم الآلي
يعتمد مجال التعلم الآلي على ركيزتين أساسيتين هما التعلم تحت الإشراف والتعلم غير الخاضع للإشراف . يعتبر بعض الأشخاص أيضًا مجالًا جديدًا للدراسة - التعلم العميق - ليكون منفصلاً عن مسألة التعلم الخاضع للإشراف مقابل التعلم غير الخاضع للإشراف.
التعلم الخاضع للإشراف هو عندما يتم تقديم الكمبيوتر مع أمثلة على المدخلات والمخرجات المرغوبة. الهدف من الكمبيوتر هو تعلم صيغة عامة تحدد المدخلات إلى المخرجات. يمكن تقسيم ذلك إلى:
- التعلم شبه الخاضع للإشراف ، وهو عندما يتم إعطاء الكمبيوتر مجموعة تدريب غير مكتملة مع فقدان بعض المخرجات
- التعلم النشط ، وهو عندما يتمكن الكمبيوتر فقط من الحصول على ملصقات تدريبية لمجموعة محدودة جدًا من الحالات. عند استخدامها بشكل تفاعلي ، يمكن تقديم مجموعات التدريب الخاصة بهم إلى المستخدم لوضع العلامات عليها.
- التعلم المعزز ، وهو عندما يتم تقديم بيانات التدريب فقط كتعليقات على إجراءات البرنامج في البيئة الديناميكية ، مثل قيادة السيارة أو ممارسة لعبة ضد الخصم
في المقابل ، التعلم غير الخاضع للإشراف هو عندما لا يتم إعطاء أي تسميات على الإطلاق ويتعين على الخوارزمية العثور على الهيكل في مدخلاتها. يمكن أن يكون التعلم غير الخاضع للإشراف هدفًا في حد ذاته عندما نحتاج فقط إلى اكتشاف الأنماط المخفية.
التعلم العميق هو مجال جديد للدراسة مستوحى من بنية ووظيفة الدماغ البشري ويعتمد على الشبكات العصبية الاصطناعية بدلاً من المفاهيم الإحصائية فقط. يمكن استخدام التعلم العميق في كل من الأساليب الخاضعة للإشراف وغير الخاضعة للإشراف.
في هذه المقالة ، سنستعرض فقط بعض خوارزميات التعلم الآلي الأبسط الخاضعة للإشراف ونستخدمها لحساب فرص البقاء على قيد الحياة لفرد في غرق تيتانيك المأساوي. ولكن بشكل عام ، إذا لم تكن متأكدًا من الخوارزمية التي يجب استخدامها ، فإن أفضل مكان للبدء هو ورقة الغش الخاصة بخوارزمية التعلم الآلي الخاصة بـ scikit-Learn.
نماذج التعلم الآلي الأساسية الخاضعة للإشراف
ربما تكون أسهل خوارزمية ممكنة هي الانحدار الخطي. في بعض الأحيان يمكن تمثيل ذلك بيانياً كخط مستقيم ، ولكن على الرغم من اسمه ، إذا كانت هناك فرضية متعددة الحدود ، فقد يكون هذا الخط بدلاً من ذلك منحنى. وفي كلتا الحالتين ، فإنه يصوغ العلاقات بين المتغير المعتمد القياسي $ y $ وقيم توضيحي واحد أو أكثر يُشار إليه بـ $ x $.
من منظور الشخص العادي ، يعني هذا أن الانحدار الخطي هو الخوارزمية التي تتعلم التبعية بين كل $ x $ و $ y $ المعروفين ، بحيث يمكننا استخدامها لاحقًا للتنبؤ بـ $ y $ لعينة غير معروفة من $ x $.
في أول مثال تعليمي خاضع للإشراف ، سنستخدم نموذج الانحدار الخطي الأساسي للتنبؤ بضغط دم الشخص بالنظر إلى عمره. هذه مجموعة بيانات بسيطة للغاية ذات سمتين مهمتين: العمر وضغط الدم.
كما ذكرنا سابقًا ، تعمل معظم خوارزميات التعلم الآلي من خلال إيجاد تبعية إحصائية في البيانات المقدمة لهم. تسمى هذه التبعية الفرضية وعادة ما يُرمز إليها ب $ h (\ theta) $.
لمعرفة الفرضية ، لنبدأ بتحميل البيانات واستكشافها.
import matplotlib.pyplot as plt from pandas import read_csv import os # Load data data_path = os.path.join(os.getcwd(), "data/blood-pressure.txt") dataset = read_csv(data_path, delim_whitespace=True) # We have 30 entries in our dataset and four features. The first feature is the ID of the entry. # The second feature is always 1. The third feature is the age and the last feature is the blood pressure. # We will now drop the ID and One feature for now, as this is not important. dataset = dataset.drop(['ID', 'One'], axis=1) # And we will display this graph %matplotlib inline dataset.plot.scatter(x='Age', y='Pressure') # Now, we will assume that we already know the hypothesis and it looks like a straight line h = lambda x: 84 + 1.24 * x # Let's add this line on the chart now ages = range(18, 85) estimated = [] for i in ages: estimated.append(h(i)) plt.plot(ages, estimated, 'b')
[<matplotlib.lines.Line2D at 0x11424b828>]
في الرسم البياني أعلاه ، تمثل كل نقطة زرقاء عينة بياناتنا والخط الأزرق هو الفرضية التي تحتاج خوارزميتنا إلى تعلمها. إذن ما هي هذه الفرضية بالضبط على أي حال؟
لحل هذه المشكلة ، نحتاج إلى معرفة التبعية بين $ x $ و $ y $ ، والمشار إليها بـ $ y = f (x) $. لذلك فإن $ f (x) $ هي دالة الهدف المثالية. ستحاول خوارزمية التعلم الآلي تخمين دالة الفرضية $ h (x) $ وهي أقرب تقريب للمجهول $ f (x) $.
يبدو أبسط شكل ممكن من الفرضيات لمشكلة الانحدار الخطي كما يلي: $ h_ \ theta (x) = \ theta_0 + \ theta_1 * x $. لدينا متغير قياسي واحد للإدخال $ x $ والذي ينتج متغيرًا قياسيًا واحدًا $ y $ ، حيث $ \ theta_0 $ و $ \ theta_1 $ معلمتان نحتاج إلى تعلمهما. تسمى عملية احتواء هذا الخط الأزرق في البيانات الانحدار الخطي. من المهم أن نفهم أن لدينا معلمة إدخال واحدة فقط $ x_1 $؛ ومع ذلك ، فإن الكثير من وظائف الفرضيات ستتضمن أيضًا وحدة التحيز ($ x_0 $). لذا فإن الفرضية الناتجة لها شكل $ h_ \ theta (x) = \ theta_0 * x_0 + \ theta_1 * x_1 $. لكن يمكننا تجنب كتابة $ x_0 $ لأنه دائمًا ما يساوي 1.
العودة إلى الخط الأزرق. تبدو فرضيتنا مثل $ h (x) = 84 + 1.24x $ ، مما يعني أن $ \ theta_0 = 84 $ و $ \ theta_1 = 1.24 $. كيف يمكننا اشتقاق قيم $ \ theta $ هذه تلقائيًا؟
نحن بحاجة إلى تحديد دالة التكلفة . بشكل أساسي ، ما تقوم به دالة التكلفة هو ببساطة حساب جذر متوسط الخطأ التربيعي بين توقع النموذج والمخرجات الفعلية.
\ [J (\ theta) = \ frac {1} {2m} \ sum_ {i = 1} ^ m (h_ \ theta (x ^ {(i)}) - y ^ {(i)}) ^ 2 \ ]على سبيل المثال ، تتوقع فرضيتنا أنه بالنسبة لشخص يبلغ من العمر 48 عامًا ، يجب أن يكون ضغط دمه $ h (48) = 84 + 1.24 * 48 = 143mmHg $ ؛ ومع ذلك ، في نموذج التدريب لدينا ، لدينا قيمة $ 130 mmHg $. لذلك الخطأ هو $ (143-130) ^ 2 = 169 $. نحتاج الآن إلى حساب هذا الخطأ لكل إدخال فردي في مجموعة بيانات التدريب الخاصة بنا ، ثم نجمعها معًا ($ \ sum_ {i = 1} ^ m (h_ \ theta (x ^ {(i)}) - y ^ {(i )}) ^ 2 $) واستخرج متوسط القيمة من ذلك.
هذا يعطينا رقمًا قياسيًا واحدًا يمثل تكلفة الوظيفة. هدفنا هو العثور على قيم $ \ theta $ بحيث تكون دالة التكلفة هي الأدنى ؛ بعبارة أخرى ، نريد تقليل دالة التكلفة. نأمل أن يبدو هذا بديهيًا: إذا كانت لدينا قيمة دالة تكلفة صغيرة ، فهذا يعني أن خطأ التنبؤ صغير أيضًا.
import numpy as np # Let's calculate the cost for the hypothesis above h = lambda x, theta_0, theta_1: theta_0 + theta_1 * x def cost(X, y, t0, t1): m = len(X) # the number of the training samples c = np.power(np.subtract(h(X, t0, t1), y), 2) return (1 / (2 * m)) * sum(c) X = dataset.values[:, 0] y = dataset.values[:, 1] print('J(Theta) = %2.2f' % cost(X, y, 84, 1.24))
J(Theta) = 1901.95
الآن ، نحتاج إلى إيجاد قيم $ \ theta $ بحيث تكون قيمة دالة التكلفة لدينا ضئيلة. لكن كيف نفعل ذلك؟
\ [minJ (\ theta) = \ frac {1} {2m} \ sum_ {i = 1} ^ m (h_ \ theta (x ^ {(i)}) - y ^ {(i)}) ^ 2 \ ]هناك العديد من الخوارزميات الممكنة ، ولكن الأكثر شيوعًا هو النسب المتدرج . لفهم الحدس الكامن وراء طريقة النسب المتدرج ، دعنا نرسمه أولاً على الرسم البياني. من أجل التبسيط ، سنفترض فرضية أبسط $ h (\ theta) = \ theta_1 * x $. بعد ذلك ، سنرسم مخططًا بسيطًا ثنائي الأبعاد حيث $ x $ هي قيمة $ \ theta $ و $ y $ هي دالة التكلفة في هذه المرحلة.
import matplotlib.pyplot as plt fig = plt.figure() # Generate the data theta_1 = np.arange(-10, 14, 0.1) J_cost = [] for t1 in theta_1: J_cost += [ cost(X, y, 0, t1) ] plt.plot(theta_1, J_cost) plt.xlabel(r'$\theta_1$') plt.ylabel(r'$J(\theta)$') plt.show()
دالة التكلفة محدبة ، مما يعني أنه في الفاصل الزمني $ [a، b] $ يوجد حد أدنى واحد فقط. مما يعني مرة أخرى أن أفضل معلمات $ \ theta $ تكون عند النقطة التي تكون فيها دالة التكلفة ضئيلة.
في الأساس ، نزول التدرج هو خوارزمية تحاول العثور على مجموعة من المعلمات التي تقلل من الوظيفة. يبدأ بمجموعة أولية من المعلمات ويتخذ خطوات تكرارية في الاتجاه السلبي لتدرج الوظيفة.
إذا قمنا بحساب مشتقة دالة فرضية عند نقطة معينة ، فسيعطينا هذا ميلًا لخط المماس للمنحنى عند تلك النقطة. هذا يعني أنه يمكننا حساب الميل عند كل نقطة على الرسم البياني.
طريقة عمل الخوارزمية هي كالتالي:
- نختار نقطة بداية عشوائية (عشوائية $ theta $).
- احسب مشتق دالة التكلفة في هذه المرحلة.
- اتخذ الخطوة الصغيرة نحو المنحدر $ \ theta_j: = \ theta_j - \ lambda * \ frac {\ جزئي} {\ جزئي \ theta_j} * J (\ theta) $.
- كرر الخطوتين 2-3 حتى نتقارب.
الآن ، يعتمد شرط التقارب على تنفيذ الخوارزمية. قد نتوقف بعد 50 خطوة ، بعد بعض العتبة ، أو أي شيء آخر.
import math # Example of the simple gradient descent algorithm taken from Wikipedia cur_x = 2.5 # The algorithm starts at point x gamma = 0.005 # Step size multiplier precision = 0.00001 previous_step_size = cur_x df = lambda x: 2 * x * math.cos(x) # Remember the learning curve and plot it while previous_step_size > precision: prev_x = cur_x cur_x += -gamma * df(prev_x) previous_step_size = abs(cur_x - prev_x) print("The local minimum occurs at %f" % cur_x)
The local minimum occurs at 4.712194
لن ننفذ تلك الخوارزميات في هذه المقالة. بدلاً من ذلك ، سوف نستخدم scikit-learn
المعتمدة على نطاق واسع ، وهي مكتبة تعلم آلة Python مفتوحة المصدر. إنه يوفر الكثير من واجهات برمجة التطبيقات المفيدة جدًا لمشاكل التنقيب عن البيانات المختلفة وتعلم الآلة.
from sklearn.linear_model import LinearRegression # LinearRegression uses the gradient descent method # Our data X = dataset[['Age']] y = dataset[['Pressure']] regr = LinearRegression() regr.fit(X, y) # Plot outputs plt.xlabel('Age') plt.ylabel('Blood pressure') plt.scatter(X, y, color='black') plt.plot(X, regr.predict(X), color='blue') plt.show() plt.gcf().clear()
<matplotlib.figure.Figure at 0x120fae1d0>
print( 'Predicted blood pressure at 25 yo = ', regr.predict(25) ) print( 'Predicted blood pressure at 45 yo = ', regr.predict(45) ) print( 'Predicted blood pressure at 27 yo = ', regr.predict(27) ) print( 'Predicted blood pressure at 34.5 yo = ', regr.predict(34.5) ) print( 'Predicted blood pressure at 78 yo = ', regr.predict(78) )
Predicted blood pressure at 25 yo = [[ 122.98647692]] Predicted blood pressure at 45 yo = [[ 142.40388395]] Predicted blood pressure at 27 yo = [[ 124.92821763]] Predicted blood pressure at 34.5 yo = [[ 132.20974526]] Predicted blood pressure at 78 yo = [[ 174.44260555]]
أنواع البيانات الإحصائية
عند العمل باستخدام البيانات الخاصة بمشكلات التعلم الآلي ، من المهم التعرف على أنواع البيانات المختلفة. قد يكون لدينا بيانات عددية (مستمرة أو منفصلة) أو فئوية أو ترتيبية.
البيانات العددية لها معنى كقياس. على سبيل المثال ، العمر أو الوزن أو عدد عملات البيتكوين التي يمتلكها الشخص أو عدد المقالات التي يمكن للشخص كتابتها شهريًا. يمكن تقسيم البيانات العددية إلى أنواع منفصلة ومستمرة.
- تمثل البيانات المنفصلة البيانات التي يمكن عدها بأرقام صحيحة ، على سبيل المثال ، عدد الغرف في شقة أو عدد تقلبات العملات المعدنية.
- لا يمكن بالضرورة تمثيل البيانات المستمرة بأرقام صحيحة. على سبيل المثال ، إذا كنت تقيس المسافة التي يمكنك القفز بها ، فقد تكون مترين أو 1.5 متر أو 1.652245 مترًا.
تمثل البيانات الفئوية قيمًا مثل جنس الشخص ، والحالة الاجتماعية ، والبلد ، وما إلى ذلك. يمكن أن تأخذ هذه البيانات قيمة عددية ، لكن هذه الأرقام ليس لها معنى رياضي. لا يمكنك جمعهم معا.
يمكن أن تكون البيانات الترتيبية مزيجًا من النوعين الآخرين ، حيث يمكن ترقيم الفئات بطريقة ذات مغزى رياضي. أحد الأمثلة الشائعة هو التصنيفات: غالبًا ما يُطلب منا تصنيف الأشياء على مقياس من واحد إلى عشرة ، ولا يُسمح إلا بالأرقام الصحيحة. بينما يمكننا استخدام هذا عدديًا - على سبيل المثال ، للعثور على متوسط تقييم لشيء ما - غالبًا ما نتعامل مع البيانات كما لو كانت قاطعة عندما يتعلق الأمر بتطبيق أساليب التعلم الآلي عليها.
الانحدار اللوجستي
الانحدار الخطي هو خوارزمية رائعة تساعدنا على التنبؤ بالقيم العددية ، على سبيل المثال ، سعر المنزل مع الحجم المحدد وعدد الغرف. ومع ذلك ، في بعض الأحيان ، قد نرغب أيضًا في توقع البيانات الفئوية للحصول على إجابات لأسئلة مثل:
- هل هذا كلب أم قطة؟
- هل هذا الورم خبيث أم حميد؟
- هل هذا النبيذ جيد أم سيء؟
- هل هذا البريد الإلكتروني غير مرغوب فيه أم لا؟
او حتى:
- أي رقم في الصورة؟
- إلى أي فئة ينتمي هذا البريد الإلكتروني؟
كل هذه الأسئلة خاصة بمشكلة التصنيف . وأبسط خوارزمية تصنيف تسمى الانحدار اللوجستي ، والتي هي في النهاية نفس الانحدار الخطي باستثناء أن لها فرضية مختلفة.
بادئ ذي بدء ، يمكننا إعادة استخدام نفس الفرضية الخطية $ h_ \ theta (x) = \ theta ^ TX $ (هذا في شكل موجه). في حين أن الانحدار الخطي قد ينتج أي رقم في الفاصل $ [a، b] $ ، فإن الانحدار اللوجستي يمكنه فقط إخراج القيم في $ [- 1، 1] $ ، وهو احتمال سقوط العنصر في فئة معينة أم لا.
باستخدام التابع السيني ، يمكننا تحويل أي قيمة عددية لتمثيل قيمة على الفترة $ [- 1 ، 1] $.
\ [f (x) = \ frac {1} {1 + e ^ x} \]الآن ، بدلاً من $ x $ ، نحتاج إلى تمرير فرضية موجودة ، وبالتالي سنحصل على:
\ [f (x) = \ frac {1} {1 + e ^ {\ theta_0 + \ theta_1 * x_1 + ... + \ theta_n * x_n}} \]بعد ذلك ، يمكننا تطبيق حد بسيط يقول أنه إذا كانت الفرضية أكبر من الصفر ، فهذه قيمة حقيقية ، وإلا فهي خاطئة.
\ [h_ \ theta (x) = \ begin {cases} 1 & \ mbox {if} \ theta ^ TX> 0 \\ 0 & \ mbox {else} \ end {cases} \]هذا يعني أنه يمكننا استخدام نفس دالة التكلفة ونفس خوارزمية نزول التدرج لتعلم فرضية الانحدار اللوجستي.
في مثالنا التالي لخوارزمية التعلم الآلي ، سننصح طياري مكوك الفضاء ما إذا كان ينبغي عليهم استخدام التحكم الآلي أو اليدوي في الهبوط أم لا. لدينا مجموعة بيانات صغيرة جدًا - 15 عينة - تتكون من ست ميزات والحقيقة الأساسية .
في خوارزميات التعلم الآلي ، يشير مصطلح " الحقيقة الأساسية " إلى دقة تصنيف مجموعة التدريب لتقنيات التعلم تحت الإشراف.
مجموعة البيانات الخاصة بنا كاملة ، مما يعني أنه لا توجد ميزات مفقودة ؛ ومع ذلك ، تحتوي بعض الميزات على علامة "*" بدلاً من الفئة ، مما يعني أن هذه الميزة غير مهمة. سنستبدل كل هذه العلامات النجمية بأصفار.
from sklearn.linear_model import LogisticRegression # Data data_path = os.path.join(os.getcwd(), "data/shuttle-landing-control.csv") dataset = read_csv(data_path, header=None, names=['Auto', 'Stability', 'Error', 'Sign', 'Wind', 'Magnitude', 'Visibility'], na_values='*').fillna(0) # Prepare features X = dataset[['Stability', 'Error', 'Sign', 'Wind', 'Magnitude', 'Visibility']] y = dataset[['Auto']].values.reshape(1, -1)[0] model = LogisticRegression() model.fit(X, y) # For now, we're missing one important concept. We don't know how well our model # works, and because of that, we cannot really improve the performance of our hypothesis. # There are a lot of useful metrics, but for now, we will validate how well # our algorithm performs on the dataset it learned from. "Score of our model is %2.2f%%" % (model.score(X, y) * 100)
Score of our model is 73.33%
تصديق؟
في المثال السابق ، تحققنا من أداء نموذجنا باستخدام بيانات التعلم. ومع ذلك ، هل هذا خيار جيد الآن ، بالنظر إلى أن الخوارزمية الخاصة بنا يمكن أن تتناسب مع البيانات بشكل زائد؟ دعنا نلقي نظرة على المثال الأبسط عندما يكون لدينا ميزة واحدة تمثل حجم المنزل وأخرى تمثل سعره.
from sklearn.pipeline import make_pipeline from sklearn.preprocessing import PolynomialFeatures from sklearn.linear_model import LinearRegression from sklearn.model_selection import cross_val_score # Ground truth function ground_truth = lambda X: np.cos(15 + np.pi * X) # Generate random observations around the ground truth function n_samples = 15 degrees = [1, 4, 30] X = np.linspace(-1, 1, n_samples) y = ground_truth(X) + np.random.randn(n_samples) * 0.1 plt.figure(figsize=(14, 5)) models = {} # Plot all machine learning algorithm models for idx, degree in enumerate(degrees): ax = plt.subplot(1, len(degrees), idx + 1) plt.setp(ax, xticks=(), yticks=()) # Define the model polynomial_features = PolynomialFeatures(degree=degree) model = make_pipeline(polynomial_features, LinearRegression()) models[degree] = model # Train the model model.fit(X[:, np.newaxis], y) # Evaluate the model using cross-validation scores = cross_val_score(model, X[:, np.newaxis], y) X_test = X plt.plot(X_test, model.predict(X_test[:, np.newaxis]), label="Model") plt.scatter(X, y, edgecolor='b', s=20, label="Observations") plt.xlabel("x") plt.ylabel("y") plt.ylim((-2, 2)) plt.title("Degree {}\nMSE = {:.2e}".format( degree, -scores.mean())) plt.show()

نموذج خوارزمية التعلم الآلي غير ملائم إذا كان لا يمكن تعميم بيانات التدريب أو الملاحظات الجديدة. في المثال أعلاه ، نستخدم فرضية خطية بسيطة لا تمثل مجموعة بيانات التدريب الفعلية وسيكون أداءها ضعيفًا للغاية. عادة ، لا تتم مناقشة نقص الملاءمة لأنه يمكن اكتشافها بسهولة بمقياس جيد.
إذا تذكرت الخوارزمية الخاصة بنا كل ملاحظة تم عرضها ، فسيكون أداءها ضعيفًا في الملاحظات الجديدة خارج مجموعة بيانات التدريب. وهذا ما يسمى overfitting . على سبيل المثال ، يمر نموذج متعدد الحدود من الدرجة 30 من خلال معظم النقاط ولديه درجة جيدة جدًا في مجموعة التدريب ، ولكن أي شيء خارج ذلك سيكون أداءً سيئًا.
تتكون مجموعة البيانات الخاصة بنا من ميزة واحدة ويسهل رسمها في مساحة ثنائية الأبعاد ؛ ومع ذلك ، في الحياة الواقعية ، قد يكون لدينا مجموعات بيانات بها مئات الميزات ، مما يجعل من المستحيل رسمها بصريًا في الفضاء الإقليدي. ما هي الخيارات الأخرى المتوفرة لدينا لمعرفة ما إذا كان النموذج غير ملائم أو غير ملائم؟
حان الوقت لتعريفك بمفهوم منحنى التعلم . هذا رسم بياني بسيط يرسم متوسط الخطأ التربيعي على عدد عينات التدريب.
سترى عادةً في المواد التعليمية رسومًا بيانية مشابهة لما يلي:
ومع ذلك ، في الحياة الواقعية ، قد لا تحصل على مثل هذه الصورة المثالية. دعنا نرسم منحنى التعلم لكل نموذج من نماذجنا.
from sklearn.model_selection import learning_curve, ShuffleSplit # Plot learning curves plt.figure(figsize=(20, 5)) for idx, degree in enumerate(models): ax = plt.subplot(1, len(degrees), idx + 1) plt.title("Degree {}".format(degree)) plt.grid() plt.xlabel("Training examples") plt.ylabel("Score") train_sizes = np.linspace(.6, 1.0, 6) # Cross-validation with 100 iterations to get a smoother mean test and training # score curves, each time with 20% of the data randomly selected as a validation set. cv = ShuffleSplit(n_splits=100, test_size=0.2, random_state=0) model = models[degree] train_sizes, train_scores, test_scores = learning_curve( model, X[:, np.newaxis], y, cv=cv, train_sizes=train_sizes, n_jobs=4) train_scores_mean = np.mean(train_scores, axis=1) test_scores_mean = np.mean(test_scores, axis=1) plt.plot(train_sizes, train_scores_mean, 'o-', color="r", label="Training score") plt.plot(train_sizes, test_scores_mean, 'o-', color="g", label="Test score") plt.legend(loc = "best") plt.show()
في سيناريو المحاكاة الخاص بنا ، يبدو الخط الأزرق ، الذي يمثل درجة التدريب ، كخط مستقيم. في الواقع ، لا يزال يتناقص بشكل طفيف - يمكنك في الواقع رؤية هذا في الرسم البياني متعدد الحدود من الدرجة الأولى ، ولكن في الرسوم الأخرى يكون دقيقًا جدًا لدرجة عدم القدرة على تحديد هذا الدقة. نحن نرى بوضوح على الأقل أن هناك فجوة كبيرة بين منحنيات التعلم للتدريب واختبار الملاحظات مع سيناريو "التحيز العالي".
على الرسم البياني لمعدل التعلم "العادي" في المنتصف ، يمكنك أن ترى كيف يتم تجميع درجات التدريب وخطوط درجات الاختبار معًا.
وعلى الرسم البياني "التباين العالي" ، يمكنك أن ترى أنه مع وجود عدد قليل من العينات ، فإن درجات الاختبار والتدريب متشابهة جدًا ؛ ومع ذلك ، عند زيادة عدد العينات ، تظل درجة التدريب مثالية تقريبًا بينما تزداد درجة الاختبار بعيدًا عنها.
يمكننا إصلاح النماذج غير الملائمة (وتسمى أيضًا النماذج ذات التحيز العالي ) إذا استخدمنا فرضية غير خطية ، على سبيل المثال ، الفرضية ذات الميزات متعددة الحدود.
يمر نموذج التجاوز ( التباين العالي ) الخاص بنا من خلال كل مثال يتم عرضه ؛ ومع ذلك ، عندما نقدم بيانات الاختبار ، تتسع الفجوة بين منحنيات التعلم. يمكننا استخدام التنظيم والتحقق المتبادل والمزيد من عينات البيانات لإصلاح نماذج التجهيز الزائد.
عبر المصادقة
تتمثل إحدى الممارسات الشائعة لتجنب فرط التخصيص في الاحتفاظ بجزء من البيانات المتاحة واستخدامه كمجموعة اختبار. ومع ذلك ، عند تقييم إعدادات النموذج المختلفة ، مثل عدد الميزات متعددة الحدود ، فإننا لا نزال معرضين لخطر التلاعب بمجموعة الاختبار لأنه يمكن تعديل المعلمات لتحقيق الأداء الأمثل للمقدر ، وبسبب ذلك ، فإن معرفتنا بمجموعة الاختبار يمكن تسرب إلى النموذج. لحل هذه المشكلة ، نحتاج إلى التمسك بجزء آخر من مجموعة البيانات ، والذي يسمى "مجموعة التحقق من الصحة". يستمر التدريب على مجموعة التدريب ، وعندما نعتقد أننا حققنا الأداء الأمثل للنموذج ، يمكننا إجراء تقييم نهائي باستخدام مجموعة التحقق من الصحة.
ومع ذلك ، من خلال تقسيم البيانات المتاحة إلى ثلاث مجموعات ، فإننا نخفض بشكل كبير عدد العينات التي يمكن استخدامها لتدريب النماذج ، ويمكن أن تعتمد النتائج على اختيار عشوائي معين لمجموعات التحقق من التدريب.
أحد الحلول لهذه المشكلة هو إجراء يسمى التحقق المتبادل. في التحقق المتقاطع القياسي $ k $ -fold ، نقوم بتقسيم البيانات إلى مجموعات فرعية $ k $ ، تسمى الطيات. بعد ذلك ، نقوم بتدريب الخوارزمية بشكل متكرر على طيات $ k-1 $ أثناء استخدام الطية المتبقية كمجموعة اختبار (تسمى "حظيرة الانتظار").
يسمح لك التحقق المتقاطع بضبط المعلمات باستخدام مجموعة التدريب الأصلية فقط. يسمح لك هذا بالحفاظ على مجموعة اختبارك كمجموعة بيانات غير مرئية حقًا لاختيار نموذجك النهائي.
هناك الكثير من تقنيات التحقق المتبادل ، مثل ترك P خارج ، وطبقية $ k $ -fold ، و shuffle and split ، وما إلى ذلك ، لكنها خارج نطاق هذه المقالة.
تنظيم
هذه تقنية أخرى يمكن أن تساعد في حل مشكلة تعديل النموذج. تحتوي معظم مجموعات البيانات على نمط وبعض الضوضاء. الهدف من التنظيم هو تقليل تأثير الضوضاء على النموذج.
هناك ثلاث تقنيات تنظيم رئيسية: لاسو وتيخونوف والشبكة المرنة.
سيحدد تنظيم L1 (أو تنظيم Lasso ) بعض الميزات لتقليصها إلى الصفر ، بحيث لا تلعب أي دور في النموذج النهائي. يمكن اعتبار L1 كطريقة لتحديد الميزات المهمة.
سيؤدي تنظيم L2 (أو تنظيم Tikhonov ) إلى إجبار جميع الميزات على أن تكون صغيرة نسبيًا ، بحيث توفر تأثيرًا أقل على النموذج.
الشبكة المرنة هي مزيج من L1 و L2.
التطبيع (تحجيم الميزة)
يعد تحجيم الميزة أيضًا خطوة مهمة أثناء المعالجة المسبقة للبيانات. قد تحتوي مجموعة البيانات الخاصة بنا على ميزات ذات قيم $ [- \ infty، \ infty] $ وميزات أخرى بمقياس مختلف. هذه طريقة لتوحيد نطاقات القيم المستقلة.
مقياس الميزات هو أيضًا عملية مهمة لتحسين أداء نماذج التعلم. بادئ ذي بدء ، سوف يتقارب نزول التدرج بشكل أسرع إذا تم تحجيم جميع الميزات بنفس المعيار. أيضًا ، تعمل الكثير من الخوارزميات - على سبيل المثال ، آلات المتجه (SVM) - من خلال حساب المسافة بين نقطتين وإذا كانت إحدى الميزات لها قيم واسعة ، فستتأثر المسافة بشدة بهذه الميزة.
دعم آلات المتجهات
تعد SVM خوارزمية أخرى للتعلم الآلي شائعة على نطاق واسع والتي يمكن استخدامها لمشاكل التصنيف والانحدار. في SVM ، نرسم كل ملاحظة كنقطة في مساحة الأبعاد $ n $ حيث $ n $ هو عدد الميزات التي لدينا. قيمة كل معلم هي قيمة إحداثيات معينة. ثم نحاول إيجاد مستوي فائق يفصل بين فئتين جيدًا.
بعد تحديد أفضل مستوى فائق ، نريد إضافة هوامش ، والتي من شأنها فصل الفئتين بشكل أكبر.
يعد SVM فعالاً للغاية عندما يكون عدد الميزات مرتفعًا جدًا أو إذا كان عدد الميزات أكبر من عدد عينات البيانات. ومع ذلك ، نظرًا لأن SVM يعمل على أساس متجه ، فمن الضروري تطبيع البيانات قبل الاستخدام.
الشبكات العصبية
ربما تكون خوارزميات الشبكة العصبية هي المجال الأكثر إثارة في دراسات التعلم الآلي. تحاول الشبكات العصبية محاكاة كيفية ارتباط الخلايا العصبية في الدماغ ببعضها البعض.
هكذا تبدو الشبكة العصبية. نحن نجمع الكثير من العقد معًا حيث تأخذ كل عقدة مجموعة من المدخلات ، ونطبق بعض الحسابات عليها ، ونخرج قيمة.
هناك مجموعة كبيرة ومتنوعة من خوارزميات الشبكة العصبية لكل من التعلم الخاضع للإشراف والتعلم غير الخاضع للإشراف. يمكن استخدام الشبكات العصبية لقيادة السيارات ذاتية القيادة ولعب الألعاب والطائرات الأرضية وتصنيف الصور والمزيد.
تايتانيك سيئ السمعة
كانت RMS Titanic سفينة ركاب بريطانية غرقت في شمال المحيط الأطلسي في 15 أبريل 1912 بعد اصطدامها بجبل جليدي. كان هناك حوالي 2224 من أفراد الطاقم والركاب ، وتوفي أكثر من 1500 ، مما يجعلها واحدة من أكثر الكوارث البحرية التجارية فتكًا على الإطلاق.
الآن ، نظرًا لأننا نفهم الحدس الكامن وراء خوارزميات التعلم الآلي الأساسية المستخدمة في مشاكل التصنيف ، يمكننا تطبيق معرفتنا للتنبؤ بنتيجة البقاء على متن السفينة تايتانيك.
سيتم استعارة مجموعة البيانات الخاصة بنا من منصة مسابقات علوم البيانات Kaggle.
import os from pandas import read_csv, concat # Load data data_path = os.path.join(os.getcwd(), "data/titanic.csv") dataset = read_csv(data_path, skipinitialspace=True) dataset.head(5)
PassengerId | نجا | Pclass | اسم | الجنس | سن | SibSp | بارش | تذكرة | أجرة | الطائرة | شرعت | |
0 | 1 | 0 | 3 | براوند ، السيد أوين هاريس | الذكر | 22.0 | 1 | 0 | أ / 5 21171 | 7.2500 | ن | س |
1 | 2 | 1 | 1 | Cumings ، السيدة جون برادلي (فلورنس بريجز ث ... | أنثى | 38.0 | 1 | 0 | كمبيوتر 17599 | 71.2833 | ج 85 | ج |
2 | 3 | 1 | 3 | هيكينين ، آنسة. لينا | أنثى | 26.0 | 0 | 0 | حجر / O2. 3101282 | 7.9250 | ن | س |
3 | 4 | 1 | 1 | فوتريل ، السيدة جاك هيث (ليلي ماي بيل) | أنثى | 35.0 | 1 | 0 | 113803 | 53.1000 | ق 123 | س |
4 | 5 | 0 | 3 | ألين ، السيد ويليام هنري | الذكر | 35.0 | 0 | 0 | 373450 | 8.0500 | ن | س |
ستكون خطوتنا الأولى هي تحميل البيانات واستكشافها. لدينا 891 سجل اختبار ؛ يحتوي كل سجل على الهيكل التالي:
- الركابId - معرف الراكب على متن الطائرة
- البقاء على قيد الحياة - سواء نجا الشخص من الحادث أم لا
- pclass - فئة التذاكر ، على سبيل المثال ، الأول والثاني والثالث
- الجنس - جنس المسافر: ذكر أو أنثى
- الاسم - العنوان متضمن
- العمر - العمر بالسنوات
- sibsp - عدد الأشقاء / الأزواج على متن تيتانيك
- بارش - عدد الآباء / الأطفال على متن تيتانيك
- التذكرة - رقم التذكرة
- الأجرة - أجرة الركاب
- المقصورة - رقم المقصورة
- شرعت - ميناء المغادرة
تحتوي مجموعة البيانات هذه على بيانات عددية وفئوية. عادة ، من الجيد التعمق في البيانات والتوصل إلى افتراضات بناءً على ذلك. ومع ذلك ، في هذه الحالة ، سنتخطى هذه الخطوة وننتقل مباشرة إلى التنبؤات.
import pandas as pd # We need to drop some insignificant features and map the others. # Ticket number and fare should not contribute much to the performance of our models. # Name feature has titles (eg, Mr., Miss, Doctor) included. # Gender is definitely important. # Port of embarkation may contribute some value. # Using port of embarkation may sound counter-intuitive; however, there may # be a higher survival rate for passengers who boarded in the same port. dataset['Title'] = dataset.Name.str.extract(' ([A-Za-z]+)\.', expand=False) dataset = dataset.drop(['PassengerId', 'Ticket', 'Cabin', 'Name'], axis=1) pd.crosstab(dataset['Title'], dataset['Sex'])
Title \ Sex | female | الذكر |
Capt | 0 | 1 |
Col | 0 | 2 |
الكونتيسة | 1 | 0 |
اتشح | 0 | 1 |
Dr | 1 | 6 |
جونكير | 0 | 1 |
Lady | 1 | 0 |
رائد | 0 | 2 |
رئيس | 0 | 40 |
Miss | 182 | 0 |
Mlle | 2 | 0 |
Mme | 1 | 0 |
Mr | 0 | 517 |
Mrs | 125 | 0 |
Ms | 1 | 0 |
Rev | 0 | 6 |
سيدي المحترم | 0 | 1 |
# We will replace many titles with a more common name, English equivalent, # or reclassification dataset['Title'] = dataset['Title'].replace(['Lady', 'Countess','Capt', 'Col',\ 'Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Other') dataset['Title'] = dataset['Title'].replace('Mlle', 'Miss') dataset['Title'] = dataset['Title'].replace('Ms', 'Miss') dataset['Title'] = dataset['Title'].replace('Mme', 'Mrs') dataset[['Title', 'Survived']].groupby(['Title'], as_index=False).mean()
لقب | Survived | |
0 | رئيس | 0.575000 |
1 | Miss | 0.702703 |
2 | Mr | 0.156673 |
3 | Mrs | 0.793651 |
4 | آخر | 0.347826 |
# Now we will map alphanumerical categories to numbers title_mapping = { 'Mr': 1, 'Miss': 2, 'Mrs': 3, 'Master': 4, 'Other': 5 } gender_mapping = { 'female': 1, 'male': 0 } port_mapping = { 'S': 0, 'C': 1, 'Q': 2 } # Map title dataset['Title'] = dataset['Title'].map(title_mapping).astype(int) # Map gender dataset['Sex'] = dataset['Sex'].map(gender_mapping).astype(int) # Map port freq_port = dataset.Embarked.dropna().mode()[0] dataset['Embarked'] = dataset['Embarked'].fillna(freq_port) dataset['Embarked'] = dataset['Embarked'].map(port_mapping).astype(int) # Fix missing age values dataset['Age'] = dataset['Age'].fillna(dataset['Age'].dropna().median()) dataset.head()
Survived | Pclass | الجنس | سن | SibSp | Parch | أجرة | Embarked | لقب | |
0 | 0 | 3 | 0 | 22.0 | 1 | 0 | 7.2500 | 0 | 1 |
1 | 1 | 1 | 1 | 38.0 | 1 | 0 | 71.2833 | 1 | 3 |
2 | 1 | 3 | 1 | 26.0 | 0 | 0 | 7.9250 | 0 | 2 |
3 | 1 | 1 | 1 | 35.0 | 1 | 0 | 53.1000 | 0 | 3 |
4 | 0 | 3 | 0 | 35.0 | 0 | 0 | 8.0500 | 0 | 1 |
At this point, we will rank different types of machine learning algorithms in Python by using scikit-learn
to create a set of different models. It will then be easy to see which one performs the best.
- Logistic regression with varying numbers of polynomials
- Support vector machine with a linear kernel
- Support vector machine with a polynomial kernel
- الشبكة العصبية
For every single model, we will use $k$-fold validation.
from sklearn.model_selection import KFold, train_test_split from sklearn.pipeline import make_pipeline from sklearn.preprocessing import PolynomialFeatures, StandardScaler from sklearn.neural_network import MLPClassifier from sklearn.svm import SVC # Prepare the data X = dataset.drop(['Survived'], axis = 1).values y = dataset[['Survived']].values X = StandardScaler().fit_transform(X) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state = None) # Prepare cross-validation (cv) cv = KFold(n_splits = 5, random_state = None) # Performance p_score = lambda model, score: print('Performance of the %s model is %0.2f%%' % (model, score * 100)) # Classifiers names = [ "Logistic Regression", "Logistic Regression with Polynomial Hypotheses", "Linear SVM", "RBF SVM", "Neural Net", ] classifiers = [ LogisticRegression(), make_pipeline(PolynomialFeatures(3), LogisticRegression()), SVC(kernel="linear", C=0.025), SVC(gamma=2, C=1), MLPClassifier(alpha=1), ]
# iterate over classifiers models = [] trained_classifiers = [] for name, clf in zip(names, classifiers): scores = [] for train_indices, test_indices in cv.split(X): clf.fit(X[train_indices], y[train_indices].ravel()) scores.append( clf.score(X_test, y_test.ravel()) ) min_score = min(scores) max_score = max(scores) avg_score = sum(scores) / len(scores) trained_classifiers.append(clf) models.append((name, min_score, max_score, avg_score)) fin_models = pd.DataFrame(models, columns = ['Name', 'Min Score', 'Max Score', 'Mean Score'])
fin_models.sort_values(['Mean Score']).head()
اسم | Min Score | Max Score | Mean Score | |
2 | Linear SVM | 0.793296 | 0.821229 | 0.803352 |
0 | Logistic Regression | 0.826816 | 0.860335 | 0.846927 |
4 | Neural Net | 0.826816 | 0.860335 | 0.849162 |
1 | Logistic Regression with Polynomial Hypotheses | 0.854749 | 0.882682 | 0.869274 |
3 | RBF SVM | 0.843575 | 0.888268 | 0.869274 |
Ok, so our experimental research says that the SVM classifier with a radial basis function (RBF) kernel performs the best. Now, we can serialize our model and re-use it in production applications.
import pickle svm_model = trained_classifiers[3] data_path = os.path.join(os.getcwd(), "best-titanic-model.pkl") pickle.dump(svm_model, open(data_path, 'wb'))
Machine learning is not complicated, but it's a very broad field of study, and it requires knowledge of math and statistics in order to grasp all of its concepts.
Right now, machine learning and deep learning are among the hottest topics of discussion in Silicon Valley, and are the bread and butter of almost every data science company, mainly because they can automate many repetitive tasks including speech recognition, driving vehicles, financial trading, caring for patients, cooking, marketing, and so on.
Now you can take this knowledge and solve challenges on Kaggle.
This was a very brief introduction to supervised machine learning algorithms. Luckily, there are a lot of online courses and information about machine learning algorithms. I personally would recommend starting with Andrew Ng's course on Coursera.
موارد
- Andrew Ng's course on Coursera
- Kaggle datasets
- A deep learning reading list
- A list of free books on machine learning algorithms, data mining, deep learning, and related topics
- مقدمة في نظرية التعلم الآلي وتطبيقاتها: دروس مرئية بأمثلة