{"id":"l-ml-2-1","courseId":"ml-crash-course","lang":"ar","kind":"lesson","summary":"درّب نموذج انحدار خطي باستخدام scikit-learn، واقرأ الـ intercept والمعاملات، واحكم عليه بمقاييس MAE وRMSE وR² مقارنةً بخط أساس يتنبأ بالمتوسط.","html":"<p>انقطاع العملاء سؤال إجابته نعم أو لا، وستعود إليه في القسم 3. الانحدار يأتي أولًا لأن أبسط نماذجه، الخط المستقيم، يتيح لك أن ترى بالضبط ما يعنيه “التعلّم”: اختيار أرقام تجعل التنبؤات تخطئ بأقل قدر ممكن.</p>\n<p>البيانات هي مجموعة بيانات السكري في scikit-learn: 442 مريضًا، لكلٍّ منهم عشرة قياسات أولية (العمر والجنس ومؤشر كتلة الجسم وضغط الدم وست قراءات لمصل الدم <code dir=\"ltr\">s1</code>–<code dir=\"ltr\">s6</code>)، وهدف يقيس مدى تقدّم المرض بعد عام. الـ features ممركزة ومُعايَرة مسبقًا، ولهذا تبدو ككسور عشرية صغيرة.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">feature واحد، وخط واحد</h2>\n<p>ابدأ بمؤشر كتلة الجسم وحده. يتنبأ الانحدار الخطي بـ <code dir=\"ltr\">progression = intercept + coef * bmi</code>، ويختار <code dir=\"ltr\">fit</code> الرقمين.</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"python\" data-run=\"python\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Python</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn code-run\" data-action=\"run\" data-lang=\"python\" data-index=\"0\" aria-label=\"شغّل هذا المثال\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\"/></svg><span>تشغيل</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.datasets </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> load_diabetes</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.linear_model </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> LinearRegression</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.model_selection </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> train_test_split</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">X, y </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> load_diabetes(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">return_X_y</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">True</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">as_frame</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">True</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">X_train, X_test, y_train, y_test </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> train_test_split(X, y, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">test_size</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0.25</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">random_state</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">42</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">line </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> LinearRegression().fit(X_train[[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"bmi\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]], y_train)</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"intercept:\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">round</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(line.intercept_, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">))</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"coef for bmi:\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">round</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(line.coef_[</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">], </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">))</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"first predictions:\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, line.predict(X_test[[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"bmi\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]])[:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].round(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">))</span></span></code></pre><div class=\"run-output\" data-run-output=\"0\" hidden></div></div>\n<p>الـ intercept (الجزء المقطوع، 152) هو التنبؤ عند مؤشر كتلة جسم متوسط، لأن الـ feature ممركز عند 0. والمعامل (975) هو الميل: وحدة واحدة من مؤشر كتلة الجسم المُعايَر هذا تضيف 975 إلى التنبؤ. لاحظ الأقواس المزدوجة في <code dir=\"ltr\">X_train[[&quot;bmi&quot;]]</code>: يريد scikit-learn جدولًا ثنائي الأبعاد حتى مع feature واحد.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">البواقي ودالة الخسارة</h2>\n<p>كيف اختار <code dir=\"ltr\">fit</code> هذين الرقمين؟ لكل مريض، <strong>الباقي (residual)</strong> هو القيمة الفعلية ناقص القيمة المتنبأ بها: أي الفجوة العمودية بين النقطة والخط. وتختار طريقة المربعات الصغرى العادية (ordinary least squares) الـ intercept والميل اللذين يجعلان مجموع مربعات البواقي أصغر ما يمكن. هذا المجموع، أي الشيء الذي نسعى إلى تصغيره، هو <strong>دالة الخسارة (loss)</strong>.</p>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 640 280\" role=\"img\" aria-labelledby=\"l-ml-2-1-t1\"><defs><marker id=\"arrow-l-ml-2-1-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-ml-2-1-t1\">نقاط مبعثرة حول خط صاعد. قطع عمودية متقطعة تصل كل نقطة بالخط؛ تُربَّع هذه البواقي وتُجمع، وتختار المربعات الصغرى الخطَّ الذي يجعل هذا المجموع أصغر ما يمكن.</title>\n  <line class=\"d-line\" x1=\"60\" y1=\"240\" x2=\"600\" y2=\"240\"/>\n  <line class=\"d-line\" x1=\"60\" y1=\"240\" x2=\"60\" y2=\"20\"/>\n  <text class=\"d-label-muted\" x=\"560\" y=\"262\">bmi</text>\n  <text class=\"d-label-muted\" x=\"68\" y=\"34\">تقدّم المرض</text>\n  <path class=\"d-arrow\" d=\"M80 215 L580 55\"/>\n  <line class=\"d-dashed d-line\" x1=\"130\" y1=\"199\" x2=\"130\" y2=\"168\"/>\n  <circle class=\"d-dot\" cx=\"130\" cy=\"168\" r=\"6\"/>\n  <line class=\"d-dashed d-line\" x1=\"200\" y1=\"177\" x2=\"200\" y2=\"214\"/>\n  <circle class=\"d-dot\" cx=\"200\" cy=\"214\" r=\"6\"/>\n  <line class=\"d-dashed d-line\" x1=\"270\" y1=\"154\" x2=\"270\" y2=\"120\"/>\n  <circle class=\"d-dot\" cx=\"270\" cy=\"120\" r=\"6\"/>\n  <line class=\"d-dashed d-line\" x1=\"340\" y1=\"132\" x2=\"340\" y2=\"160\"/>\n  <circle class=\"d-dot\" cx=\"340\" cy=\"160\" r=\"6\"/>\n  <line class=\"d-dashed d-line\" x1=\"420\" y1=\"106\" x2=\"420\" y2=\"62\"/>\n  <circle class=\"d-dot\" cx=\"420\" cy=\"62\" r=\"6\"/>\n  <line class=\"d-dashed d-line\" x1=\"500\" y1=\"81\" x2=\"500\" y2=\"120\"/>\n  <circle class=\"d-dot\" cx=\"500\" cy=\"120\" r=\"6\"/>\n  <text class=\"d-label\" x=\"430\" y=\"90\">باقٍ</text>\n</svg><figcaption>البواقي هي الفجوات العمودية بين النقاط والخط</figcaption></figure>\n<p>التربيع يؤدي مهمتين: يجعل كل خطأ يُحسب موجبًا، ويجعل الأخطاء الكبيرة تُحسب أكثر بكثير من الصغيرة. خطأ مقداره 20 يكلّف 400؛ وخطأ مقداره 40 يكلّف 1,600. تذكّر هذا، لأنه يفسّر الفرق بين مقياسين من المقاييس أدناه.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">الـ features العشرة كلها</h2>\n<p>الانحدار المتعدد هو الفكرة نفسها مع حدود أكثر: معامل لكل feature، إضافة إلى الـ intercept.</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"python\" data-run=\"python\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">Python</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn code-run\" data-action=\"run\" data-lang=\"python\" data-index=\"1\" aria-label=\"شغّل هذا المثال\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\"/></svg><span>تشغيل</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.datasets </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> load_diabetes</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.linear_model </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> LinearRegression</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.model_selection </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> train_test_split</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">X, y </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> load_diabetes(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">return_X_y</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">True</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">as_frame</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">True</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">X_train, X_test, y_train, y_test </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> train_test_split(X, y, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">test_size</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0.25</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">random_state</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">42</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">model </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> LinearRegression().fit(X_train, y_train)</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> name, coef </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">in</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> zip</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(X.columns, model.coef_):</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">f</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">name</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:>4}</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> {</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">coef</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:8.1f}</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span></code></pre><div class=\"run-output\" data-run-output=\"1\" hidden></div></div>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">خطأ شائع</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>قراءة المعاملات على أنها أهمية أو سببية</span></p>\n<p>يحصل <code dir=\"ltr\">s1</code> على -918 و<code dir=\"ltr\">s2</code> على +508. كلاهما يقيس كميات مترابطة من الكوليسترول، فيرتفعان وينخفضان معًا، ويستطيع النموذج نقل الوزن بينهما بحرية شبه تامة. المعاملات الضخمة المتعاكسة على features مترابطة علامة على ذلك، لا دليل على أن <code dir=\"ltr\">s1</code> يحمي المرضى. المعاملات تصف هذا النموذج المدرَّب؛ ولا تقول شيئًا عما سيحدث لو غيّرت كيمياء دم المريض.</p>\n</aside>\n<h2 id=\"sec-4\" tabindex=\"-1\">قياس نموذج الانحدار</h2>\n<p>تعطيك <code dir=\"ltr\">score</code> قيمة R²، لكن عليك أن تعرف ثلاثة مقاييس ومتى يناسب كلٌّ منها.</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"python\" data-run=\"python\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">Python</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn code-run\" data-action=\"run\" data-lang=\"python\" data-index=\"2\" aria-label=\"شغّل هذا المثال\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\"/></svg><span>تشغيل</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.datasets </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> load_diabetes</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.dummy </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> DummyRegressor</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.linear_model </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> LinearRegression</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.metrics </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> mean_absolute_error, root_mean_squared_error, r2_score</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">from</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> sklearn.model_selection </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> train_test_split</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">X, y </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> load_diabetes(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">return_X_y</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">True</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">as_frame</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">True</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">X_train, X_test, y_train, y_test </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> train_test_split(X, y, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">test_size</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0.25</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">random_state</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">42</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">models </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">    \"mean (dummy)\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: (DummyRegressor(), X.columns),</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">    \"bmi only\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: (LinearRegression(), [</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"bmi\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]),</span></span>\n<span class=\"line\"><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">    \"all features\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: (LinearRegression(), X.columns),</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">for</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> name, (model, cols) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">in</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> models.items():</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    pred </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> model.fit(X_train[cols], y_train).predict(X_test[cols])</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">f</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">name</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:13}</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> MAE </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">mean_absolute_error(y_test, pred)</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:5.1f}</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">  \"</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">          f</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"RMSE </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">root_mean_squared_error(y_test, pred)</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:5.1f}</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">  R2 </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">r2_score(y_test, pred)</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">:6.3f}</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span></code></pre><div class=\"run-output\" data-run-output=\"2\" hidden></div></div>\n<ul>\n<li><strong>MAE</strong> (متوسط الخطأ المطلق) هو متوسط حجم الخطأ، بوحدات الهدف. “نخطئ في المتوسط بـ 42 نقطة” جملة يفهمها الطبيب أو المدير. استخدمه للتواصل.</li>\n<li><strong>RMSE</strong> (الجذر التربيعي لمتوسط مربعات الأخطاء) هو الجذر التربيعي لمتوسط الخطأ المربّع، وهو أيضًا بوحدات الهدف. وبسبب التربيع، فهو دائمًا لا يقل عن MAE، ويكون أكبر منه بكثير حين تكون بعض التنبؤات خاطئة بشدة. استخدمه حين تكون كلفة الأخطاء الكبيرة غير متناسبة.</li>\n<li><strong>R²</strong> يقارن الخطأ المربّع للنموذج بخطأ التنبؤ الدائم بالمتوسط: 1 يعني الكمال، و0 يعني أنه ليس أفضل من التنبؤ بالمتوسط، والقيمة السالبة تعني أنه أسوأ من المتوسط. لا وحدة له، فهو مفيد لمقارنة النماذج على البيانات نفسها، لكنه يُخفي حجم الأخطاء الحقيقي.</li>\n</ul>\n<p>يخفض النموذج الكامل MAE من 65.5 (خط أساس المتوسط) إلى 41.5 ويفسّر نحو نصف التباين. هذا تقدّم صادق، وتذكير أيضًا بأن نصف ما يحرّك هذا المرض ليس موجودًا في هذه الأعمدة العشرة.</p>\n<aside class=\"callout callout-tip\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">نصيحة</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>اعرض MAE بجانب R²</span></p>\n<p>“R² = 0.48” يبدو مجرّدًا، وضعيفًا في نظر غير المتخصصين. أما “خطأ معتاد مقداره 42 نقطة على مقياس يتراوح فيه المرضى بين 25 و346، بعد أن كان 66 مع التخمين الساذج” فتحكي القصة نفسها بلغة يستطيع الناس التصرّف بناءً عليها.</p>\n</aside>\n<p>استخدمت <code dir=\"ltr\">fit</code> كصندوق أسود يُعيد أفضل خط. الدرس القادم يفتح الصندوق: ستكتب بنفسك عملية البحث عن أفضل خط باستخدام الـ gradient descent، وهي الفكرة نفسها التي تُدرَّب بها الشبكات العصبية.</p>\n","toc":[{"id":"sec-1","text":"feature واحد، وخط واحد","level":2},{"id":"sec-2","text":"البواقي ودالة الخسارة","level":2},{"id":"sec-3","text":"الـ features العشرة كلها","level":2},{"id":"sec-4","text":"قياس نموذج الانحدار","level":2}],"takeaways":["يتنبأ الانحدار الخطي بـ <code dir=\"ltr\">intercept + coef1 * x1 + coef2 * x2 + …</code> ويختار الأرقام التي تجعل مجموع مربعات البواقي أصغر ما يمكن.","الباقي (residual) هو القيمة الفعلية ناقص القيمة المتنبأ بها؛ وكل مقياس انحدار هو تلخيص مختلف للبواقي.","MAE هو الخطأ المعتاد بوحدات الهدف نفسها؛ وRMSE بالوحدات نفسها لكنه يعاقب الأخطاء الكبيرة أكثر.","R² هو نسبة التباين المفسَّرة مقارنةً بالتنبؤ الدائم بالمتوسط: 0 يعني أنه ليس أفضل من المتوسط، ويمكن أن يصبح سالبًا.","معاملات الـ features المترابطة قد تكون كبيرة ومتعاكسة الإشارة، فلا تقرأها على أنها أهمية أو سببية."],"further":[{"title":"Linear Models: Ordinary Least Squares","url":"https://scikit-learn.org/stable/modules/linear_model.html#ordinary-least-squares"},{"title":"Regression metrics","url":"https://scikit-learn.org/stable/modules/model_evaluation.html#regression-metrics"},{"title":"Diabetes dataset","url":"https://scikit-learn.org/stable/datasets/toy_dataset.html#diabetes-dataset"}],"quiz":[{"q":"<p>نموذج يتنبأ بإنفاق العام القادم قيمة MAE فيه 40 دولارًا وRMSE فيه 150 دولارًا. ماذا توحي هذه الفجوة؟</p>","options":[{"text":"النموذج منحاز ويتنبأ بقيم أعلى من اللازم في المتوسط.","why":"لا يُظهر أيّ من المقياسين الاتجاه؛ فكلاهما يستخدم الأخطاء المطلقة أو المربّعة. لكشف الانحياز تنظر إلى متوسط البواقي."},{"text":"معظم الأخطاء صغيرة، لكن قليلًا منها كبير جدًا.","why":"صحيح. التربيع يجعل الأخطاء الكبيرة النادرة تهيمن على RMSE، بينما يزن MAE كل خطأ بالتساوي."},{"text":"حُسب RMSE على بيانات التدريب وMAE على بيانات الاختبار.","why":"لا شيء في الأرقام يقول ذلك. RMSE دائمًا لا يقل عن MAE على البيانات نفسها؛ والفجوة الكبيرة تتعلّق بشكل توزيع الأخطاء."}],"answer":1},{"q":"<p>يحقق نموذج قيمة R² = -0.2 على بيانات الاختبار. ماذا يعني ذلك؟</p>","options":[{"text":"أنه يفسّر 20% من التباين، في الاتجاه السالب.","why":"لا اتجاه لـ R². القيمة السالبة مقارنة مع متنبئ المتوسط، لا نسبة ذات إشارة."},{"text":"أن الحساب معطوب، لأن R² مربّع ولا يمكن أن يكون سالبًا.","why":"الاسم تاريخي. على بيانات الاختبار، R² يساوي 1 ناقص نسبة بين خطأين، وهذه النسبة قد تتجاوز 1."},{"text":"أن تنبؤاته أسوأ من التنبؤ بالمتوسط للجميع.","why":"صحيح. يقارن R² الخطأ المربّع للنموذج بخطأ التنبؤ الدائم بمتوسط القيم الفعلية؛ وما دون 0 يعني أن النموذج يخسر."}],"answer":2},{"q":"<p>في نموذج السكري، معامل <code dir=\"ltr\">s1</code> هو -918 ومعامل <code dir=\"ltr\">s2</code> هو +508. وكلاهما قياس دم متعلّق بالكوليسترول. ما القراءة الأكثر أمانًا؟</p>","options":[{"text":"<code dir=\"ltr\">s1</code> يخفض تقدّم المرض بقوة، فرفعه سيساعد المرضى.","why":"المعاملات تصف النموذج المدرَّب، لا السبب والنتيجة، والمدخلات المترابطة تجعلها غير مستقرة."},{"text":"<code dir=\"ltr\">s1</code> هو أهم feature لأن معامله الأكبر.","why":"الحجم وحده مضلِّل حين تكون الـ features مترابطة؛ فالحدّان يلغي أحدهما الآخر إلى حدّ كبير."},{"text":"هذان الـ features مترابطان، فوازن النموذج بين وزنين كبيرين متعاكسين؛ وقيمة كلٍّ منهما على حدة غير موثوقة.","why":"صحيح. مع الـ features المترابطة، تتلاءم تركيبات كثيرة من المعاملات بجودة متقاربة جدًا. والـ regularization في آخر درس من هذا القسم يروّض ذلك."}],"answer":2}],"exercise":{"kind":"python","starter":"from sklearn.datasets import load_diabetes\nfrom sklearn.linear_model import LinearRegression\nfrom sklearn.metrics import mean_absolute_error, root_mean_squared_error, r2_score\nfrom sklearn.model_selection import train_test_split\n\nX, y = load_diabetes(return_X_y=True, as_frame=True)\nX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)\ncols = [\"bmi\", \"bp\", \"s5\"]\n\n# 1. Fit a LinearRegression on the three columns in `cols`\nmodel = LinearRegression()\n\n# 2. Predict on the test rows and compute the three metrics\npred = None\nmae = None\nrmse = None\nr2 = None\n","solution":"from sklearn.datasets import load_diabetes\nfrom sklearn.linear_model import LinearRegression\nfrom sklearn.metrics import mean_absolute_error, root_mean_squared_error, r2_score\nfrom sklearn.model_selection import train_test_split\n\nX, y = load_diabetes(return_X_y=True, as_frame=True)\nX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)\ncols = [\"bmi\", \"bp\", \"s5\"]\n\nmodel = LinearRegression().fit(X_train[cols], y_train)\n\npred = model.predict(X_test[cols])\nmae = mean_absolute_error(y_test, pred)\nrmse = root_mean_squared_error(y_test, pred)\nr2 = r2_score(y_test, pred)\nprint(f\"MAE {mae:.1f}  RMSE {rmse:.1f}  R2 {r2:.3f}\")\n","checks":[{"id":"fitted","test":"hasattr(model, 'coef_') and len(model.coef_) == 3"},{"id":"pred","test":"pred is not None and len(pred) == len(y_test) and abs(float(pred[0]) - float(LinearRegression().fit(X_train[['bmi', 'bp', 's5']], y_train).predict(X_test[['bmi', 'bp', 's5']])[0])) < 1e-6"},{"id":"mae","test":"mae is not None and abs(float(mae) - float((y_test - LinearRegression().fit(X_train[['bmi', 'bp', 's5']], y_train).predict(X_test[['bmi', 'bp', 's5']])).abs().mean())) < 1e-6"},{"id":"rmse","test":"rmse is not None and abs(float(rmse) - float(((y_test - LinearRegression().fit(X_train[['bmi', 'bp', 's5']], y_train).predict(X_test[['bmi', 'bp', 's5']])) ** 2).mean() ** 0.5)) < 1e-6"},{"id":"r2","test":"r2 is not None and 0.3 < float(r2) < 0.6 and float(rmse) >= float(mae)"}],"title":"انحدار بثلاثة features، مقيس بثلاث طرق","prompt":"<p>درّب <code dir=\"ltr\">LinearRegression</code> على مؤشر كتلة الجسم وضغط الدم و<code dir=\"ltr\">s5</code> (الأعمدة الموجودة في <code dir=\"ltr\">cols</code>) وقِسه على بيانات الاختبار.</p>\n<ul>\n<li><code dir=\"ltr\">model</code>: نموذج الانحدار المدرَّب.</li>\n<li><code dir=\"ltr\">pred</code>: تنبؤاته لـ <code dir=\"ltr\">X_test[cols]</code>.</li>\n<li><code dir=\"ltr\">mae</code> و<code dir=\"ltr\">rmse</code> و<code dir=\"ltr\">r2</code>: المقاييس الثلاثة من هذا الدرس، محسوبة على بيانات الاختبار.</li>\n</ul>\n","hints":["درّب النموذج بـ <code dir=\"ltr\">model = LinearRegression().fit(X_train[cols], y_train)</code>.","تأخذ دوال المقاييس <code dir=\"ltr\">(y_true, y_pred)</code> بهذا الترتيب.","<code dir=\"ltr\">root_mean_squared_error</code> موجودة في <code dir=\"ltr\">sklearn.metrics</code>؛ وهي مستوردة مسبقًا."],"explanation":"<p>ثلاثة features مختارة جيدًا تعطي MAE بنحو 42 وR² بنحو 0.50، أي R² أعلى قليلًا مما تبلغه الـ features العشرة كلها على هذا التقسيم (0.49). وهذا أمر شائع: عدد قليل من الـ features يحمل معظم الإشارة، والـ features المترابطة الإضافية تضيف ضجيجًا إلى المعاملات. RMSE أكبر من MAE لأن حفنة من المرضى يُتنبَّأ لهم بشكل سيئ، والتربيع يجعل تلك الأخطاء تُحسب أكثر.</p>\n","checkLabels":{"fitted":"model نموذج انحدار مدرَّب على ثلاثة features","pred":"pred يحتوي تنبؤات بيانات الاختبار","mae":"mae هو متوسط الخطأ المطلق","rmse":"rmse هو الجذر التربيعي لمتوسط مربعات الأخطاء","r2":"r2 هو قيمة R² على بيانات الاختبار (وRMSE ≥ MAE)"}},"words":571,"readMinutes":3}