{"id":"l-pda-2-5","courseId":"python-data-analysis","lang":"ar","kind":"lesson","summary":"أنشئ أعمدة محسوبة بعمليات حسابية متّجهة، وابنِ أعمدة شرطية بـ ‎.loc و np.where، وحوّل الأكواد إلى تسميات، وغيّر القيم بأمان وفق قواعد Copy-on-Write في pandas.","html":"<p>في جدول <code dir=\"ltr\">order_items</code> الخاص بـ Cartwheel كمية وسعر وحدة وخصم في كل بند من بنوده الـ 3,991، لكن لا يوجد إيراد. الإيراد شيء تحسبه أنت، وطريقة حسابه يجب أن تُكتب حيث يراها الجميع. هذا ما يفعله العمود المحسوب: يحوّل قاعدة عمل إلى سطر كود واحد يُطبَّق على كل صف.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">الأعمدة المحسوبة</h2>\n<p>الإسناد إلى اسم عمود جديد ينشئه:</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\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pandas </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">as</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">items </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd.read_csv(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"order_items.csv\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"gross\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"quantity\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">*</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"unit_price\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"revenue\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"gross\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">*</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> -</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discount\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">])</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discount_amount\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"gross\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"revenue\"</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\">(items.head().to_string())</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:#0550AE;--shiki-dark:#79C0FF\">round</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"revenue\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].sum(), </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">2</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\">(items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discount_amount\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].sum(), </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">2</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>كل سطر يعمل على أعمدة كاملة، صفًا بصف، دون حلقة. النتيجة: إيراد قدره 471,940.08 دولارًا عبر كل البنود، بعد خصومات قدرها 11,658.52 دولارًا. (هذا المجموع ما زال يشمل الطلبات الملغاة؛ وستزيلها في القسم 4 حين تستطيع ربط <code dir=\"ltr\">order_items</code> بـ <code dir=\"ltr\">orders</code>.)</p>\n<p>تفعل <code dir=\"ltr\">assign()</code> الشيء نفسه، لكنها تعيد DataFrame جديدًا بدلًا من تغيير الموجود، وهذا يتيح لك تسلسل الخطوات:</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\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pandas </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">as</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">items </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:#1F2328;--shiki-dark:#E6EDF3\">    pd.read_csv(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"order_items.csv\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    .assign(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">revenue</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=lambda</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> d: d[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"quantity\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">*</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> d[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"unit_price\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">*</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> -</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> d[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discount\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]))</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    .assign(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">is_discounted</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=lambda</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> d: d[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discount\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">></span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><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\">(items[[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"revenue\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"is_discounted\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]].head(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">3</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\">(items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"is_discounted\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].sum(), </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discounted lines\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span></code></pre><div class=\"run-output\" data-run-output=\"1\" hidden></div></div>\n<p>الكود <code dir=\"ltr\">lambda d: ...</code> دالة صغيرة بلا اسم تستقبل الـ DataFrame عند تلك النقطة من السلسلة. تحتاجها حين تستخدم خطوةٌ عمودًا أُنشئ قبلها في السلسلة نفسها. الأسلوبان جيدان؛ الإسناد العادي أسهل قراءة حين تكون في البداية، والسلاسل تتألّق في دالة التنظيف التي ستكتبها في الدرس 3.5.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">الأعمدة الشرطية</h2>\n<p>التسمية بخيارين مهمة تناسب الدالة <code dir=\"ltr\">where</code> من NumPy، المكتبة التي بُنيت عليها pandas:</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\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> numpy </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">as</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> np</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pandas </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">as</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">items </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd.read_csv(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"order_items.csv\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"revenue\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"quantity\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">*</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"unit_price\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">*</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> -</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discount\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">])</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"line_size\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> np.where(items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"revenue\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">>=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 100</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"large\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"small\"</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\">(items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"line_size\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].value_counts())</span></span></code></pre><div class=\"run-output\" data-run-output=\"2\" hidden></div></div>\n<p>اقرأها هكذا: “حيث يكون الإيراد 100 على الأقل، <code dir=\"ltr\">large</code>؛ وفي غير ذلك، <code dir=\"ltr\">small</code>”. ولثلاث فئات أو أكثر، ابدأ بقيمة افتراضية ثم استبدل مجموعات فرعية بـ <code dir=\"ltr\">.loc</code>:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"python\" data-run=\"python\" data-index=\"3\"><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=\"3\" 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\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pandas </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">as</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">items </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd.read_csv(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"order_items.csv\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discount_band\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"none\"</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">items.loc[items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discount\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">></span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discount_band\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"small\"</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">items.loc[items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discount\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">></span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0.10</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discount_band\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"big\"</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discount_band\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].value_counts())</span></span></code></pre><div class=\"run-output\" data-run-output=\"3\" hidden></div></div>\n<p>الترتيب مهم تمامًا كما كان مع <code dir=\"ltr\">if</code>/<code dir=\"ltr\">elif</code> في الدرس 1.4، لكن بالعكس: الإسنادات اللاحقة تكتب فوق السابقة، فانتقل من الشرط الأوسع إلى الأضيق. الخصومات 5% و10% تنتهي في الفئة <code dir=\"ltr\">small</code>، و15% و25% في الفئة <code dir=\"ltr\">big</code>.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">ترجمة الأكواد بـ map</h2>\n<p>الأعمدة المليئة بالأكواد (<code dir=\"ltr\">mobile_app</code>، والمعرّفات، وأعلام الحالة) تحتاج غالبًا تسميات مقروءة. تترجم <code dir=\"ltr\">map()</code> مع قاموس كل قيمة:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"python\" data-run=\"python\" data-index=\"4\"><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=\"4\" 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\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pandas </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">as</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">orders </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd.read_csv(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"orders.csv\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">labels </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"web\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Website\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"mobile_app\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Mobile app\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"marketplace\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"Marketplace\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">orders[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"channel_label\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> orders[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"channel\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].map(labels)</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(orders[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"channel_label\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].value_counts())</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(orders[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"channel_label\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].isna().sum(), </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"unmapped\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span></code></pre><div class=\"run-output\" data-run-output=\"4\" hidden></div></div>\n<p>أي قيمة غير موجودة في القاموس تصبح <code dir=\"ltr\">NaN</code>، بصمت. والسطر الأخير هو الفحص الذي يلتقط ذلك: صفر قيم غير مُحوّلة يعني أن لكل قناة تسمية.</p>\n<h2 id=\"sec-4\" tabindex=\"-1\">إصلاح نوع العمود بـ astype</h2>\n<p>أحيانًا تكون القيم صحيحة لكن النوع ليس كذلك. يخزّن <code dir=\"ltr\">products.csv</code> العمود <code dir=\"ltr\">is_active</code> على هيئة 0 و1، فتقرؤه pandas أعدادًا صحيحة. الجمع يعمل، لكن قارئ كودك لا يستطيع التمييز بين علَم (flag) وعدد، وتُقرأ التصفيات بشكل متكلّف. تحوّل <code dir=\"ltr\">astype()</code> عمودًا كاملًا:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"python\" data-run=\"python\" data-index=\"5\"><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=\"5\" 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\">import</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pandas </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">as</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">products </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> pd.read_csv(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"products.csv\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">products[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"is_active\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> products[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"is_active\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].astype(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">bool</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\">(products[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"is_active\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].dtype, products[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"is_active\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].sum(), </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"active products\"</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\">(products.loc[</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">~</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">products[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"is_active\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">], </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"name\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].tolist())</span></span></code></pre><div class=\"run-output\" data-run-output=\"5\" hidden></div></div>\n<p>ثلاثة منتجات متوقّفة، و<code dir=\"ltr\">~products[&quot;is_active&quot;]</code> تُقرأ “غير نشط”. استخدم <code dir=\"ltr\">astype</code> حين يمكن تحويل كل القيم بنظافة؛ ويبيّن القسم 3 ما تفعله حين لا يمكن تحويل بعضها، مثل المجاميع التي فيها علامات دولار.</p>\n<h2 id=\"sec-5\" tabindex=\"-1\">تغيير القيم: القاعدة الوحيدة</h2>\n<p>هذه هي القاعدة التي توفّر عليك ساعات من الارتباك: <strong>لتغيير القيم في DataFrame، أسنِد إليه في خطوة واحدة</strong>، بعمود جديد أو بـ <code dir=\"ltr\">.loc[rows, column]</code>. لا تختر ثم تُسند في خطوتين أبدًا:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"python\" data-index=\"6\"><div class=\"code-head\"><span class=\"code-title\">Python</span><span class=\"code-actions\"><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:#6E7781;--shiki-dark:#8B949E\"># Wrong: chained assignment. Under Copy-on-Write this never updates items.</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discount\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">][items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discount\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">></span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0.2</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0.2</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># Right: one .loc call names the rows and the column together.</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">items.loc[items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discount\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">></span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0.2</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"discount\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0.2</span></span></code></pre></div>\n<p>الشكل الأول يختار العمود <code dir=\"ltr\">discount</code>، وهذا ينتج كائنًا جديدًا، ثم يُسند إلى ذلك الكائن. هل تغيّر <code dir=\"ltr\">items</code> نفسه؟ كان ذلك يعتمد على تفاصيل pandas الداخلية، وتطبع pandas 2 تحذير <code dir=\"ltr\">ChainedAssignmentError</code> أو <code dir=\"ltr\">SettingWithCopyWarning</code> حين تلاحظ هذا النمط. أما مع <strong>Copy-on-Write</strong> (السلوك الافتراضي منذ pandas 3.0، والمتاح في pandas 2 عبر <code dir=\"ltr\">pd.options.mode.copy_on_write = True</code>)، فتصبح القاعدة بسيطة وصارمة: كل عملية اختيار تتصرّف كنسخة، فلا يحدّث الإسناد المتسلسل الأصل أبدًا. اكتبها بطريقة <code dir=\"ltr\">.loc</code> وسيتصرّف كودك بالطريقة نفسها على كل الإصدارات.</p>\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\">q4 = orders[in_q4]</code> ثم <code dir=\"ltr\">q4[&quot;label&quot;] = &quot;Q4&quot;</code> يضيف العمود إلى <code dir=\"ltr\">q4</code> فقط. هذا سلوك صحيح وليس خطأ: الجدول المُصفّى جدول مستقل. وفي pandas 2 دون Copy-on-Write (الإصدار الذي تعمل عليه هذه الدورة) يطبع السطر الثاني أيضًا تحذير <code dir=\"ltr\">SettingWithCopyWarning</code>، لأن pandas لا تعرف أيّ الجدولين قصدت تغييره؛ والسطر <code dir=\"ltr\">q4 = orders[in_q4].copy()</code> يصرّح بأنك تريد جدولًا مستقلًا ويُسكت التحذير. وإذا كنت تقصد وضع تسمية على صفوف داخل <code dir=\"ltr\">orders</code>، فاكتب <code dir=\"ltr\">orders.loc[in_q4, &quot;label&quot;] = &quot;Q4&quot;</code>.</p>\n</aside>\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>الحذف وإعادة التسمية</span></p>\n<p>تحذف <code dir=\"ltr\">df.drop(columns=[&quot;gross&quot;])</code> الأعمدة، وتعيد <code dir=\"ltr\">df.rename(columns={&quot;unit_price&quot;: &quot;price&quot;})</code> تسميتها. كلتاهما تعيد DataFrame جديدًا، فأسنِد النتيجة: <code dir=\"ltr\">items = items.drop(columns=[&quot;gross&quot;])</code>. نسيان هذا الإسناد هو السبب الأشيع لعودة عمود ظننت أنك حذفته.</p>\n</aside>\n<p>بهذا تكتمل أساسيات pandas لديك: التحميل، والفحص، والاختيار، والتصفية، والترتيب، والحساب. يوجّه القسم 3 هذه الأدوات نحو الملف الفوضوي، حيث تنتظرك الخانات الفارغة والأخطاء الكتابية والمبالغ النصية والتواريخ الملتبسة.</p>\n","toc":[{"id":"sec-1","text":"الأعمدة المحسوبة","level":2},{"id":"sec-2","text":"الأعمدة الشرطية","level":2},{"id":"sec-3","text":"ترجمة الأكواد بـ map","level":2},{"id":"sec-4","text":"إصلاح نوع العمود بـ astype","level":2},{"id":"sec-5","text":"تغيير القيم: القاعدة الوحيدة","level":2}],"takeaways":["<code dir=\"ltr\">df[&quot;new&quot;] = expression</code> تضيف عمودًا محسوبًا لكل الصفوف دفعة واحدة؛ و<code dir=\"ltr\">assign()</code> تفعل الشيء نفسه وتعيد DataFrame جديدًا.","غيّر القيم الموجودة باستدعاء واحد <code dir=\"ltr\">.loc[row_mask, &quot;col&quot;] = value</code>، ولا تستخدم أبدًا الأقواس المتسلسلة مثل <code dir=\"ltr\">df[&quot;col&quot;][mask] = value</code>.","<code dir=\"ltr\">np.where(condition, a, b)</code> تبني عمودًا بخيارين؛ وإسنادات <code dir=\"ltr\">.loc</code> المتتالية أو <code dir=\"ltr\">np.select</code> تتعامل مع فئات أكثر.","<code dir=\"ltr\">map()</code> مع قاموس تحوّل الأكواد إلى تسميات، والقيم غير الموجودة في القاموس تصبح <code dir=\"ltr\">NaN</code>.","مع Copy-on-Write تتصرّف كل عملية اختيار كأنها نسخة، فالطريقة الوحيدة لتغيير DataFrame هي الإسناد إليه مباشرة."],"further":[{"title":"Copy-on-Write (CoW)","url":"https://pandas.pydata.org/docs/user_guide/copy_on_write.html"},{"title":"pandas.DataFrame.assign","url":"https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.assign.html"},{"title":"numpy.where","url":"https://numpy.org/doc/stable/reference/generated/numpy.where.html"}],"quiz":[{"q":"<p>تريد أن تجعل كل خصم أعلى من 0.2 مساويًا لـ 0.2. أيّ سطر يفعل ذلك بشكل صحيح في pandas 2 و3؟</p>","options":[{"text":"<code dir=\"ltr\">items[&quot;discount&quot;][items[&quot;discount&quot;] &gt; 0.2] = 0.2</code>","why":"هذا إسناد متسلسل. يختار عمودًا أولًا ثم يُسند إلى ذلك الكائن الوسيط؛ ومع Copy-on-Write لا يتغيّر الجدول الأصلي أبدًا."},{"text":"<code dir=\"ltr\">items[items[&quot;discount&quot;] &gt; 0.2][&quot;discount&quot;] = 0.2</code>","why":"متسلسل أيضًا. التصفية تنشئ جدولًا جديدًا، والإسناد يغيّر ذلك الجدول المؤقت، ويبقى <code dir=\"ltr\">items</code> كما كان."},{"text":"<code dir=\"ltr\">items.loc[items[&quot;discount&quot;] &gt; 0.2, &quot;discount&quot;] = 0.2</code>","why":"صحيح. استدعاء واحد لـ <code dir=\"ltr\">.loc</code> يسمّي الصفوف والعمود، فتُسند pandas مباشرة إلى <code dir=\"ltr\">items</code>."},{"text":"<code dir=\"ltr\">items[&quot;discount&quot;] == 0.2</code>","why":"هذا يقارن ويعيد Series منطقية؛ و<code dir=\"ltr\">==</code> لا تُسند أبدًا."}],"answer":2},{"q":"<p><code dir=\"ltr\">orders[&quot;channel_label&quot;] = orders[&quot;channel&quot;].map({&quot;web&quot;: &quot;Website&quot;, &quot;mobile_app&quot;: &quot;App&quot;})</code>. ماذا يحدث لطلبات الـ marketplace؟</p>","options":[{"text":"تحتفظ بالقيمة <code dir=\"ltr\">&quot;marketplace&quot;</code>.","why":"تستبدل <code dir=\"ltr\">map</code> كل قيمة؛ وما لا يوجد في القاموس لا يمرّ دون تغيير."},{"text":"تصبح تسميتها <code dir=\"ltr\">NaN</code>.","why":"صحيح. القيم غير الموجودة في قاموس التحويل تصبح مفقودة. افحص <code dir=\"ltr\">channel_label.isna().sum()</code> بعد كل <code dir=\"ltr\">map</code>."},{"text":"تُطلق pandas الخطأ <code dir=\"ltr\">KeyError</code>.","why":"لا تُطلق <code dir=\"ltr\">map</code> مع قاموس أي خطأ للقيم المجهولة؛ بل تملؤها بـ <code dir=\"ltr\">NaN</code>، ولهذا بالضبط يسهل أن تفوتك."}],"answer":1},{"q":"<p>ماذا ينتج <code dir=\"ltr\">np.where(items[&quot;quantity&quot;] &gt;= 3, &quot;bulk&quot;, &quot;regular&quot;)</code>؟</p>","options":[{"text":"مصفوفة فيها <code dir=\"ltr\">&quot;bulk&quot;</code> أو <code dir=\"ltr\">&quot;regular&quot;</code> لكل صف، تستطيع إسنادها كعمود جديد","why":"صحيح. تختار <code dir=\"ltr\">np.where</code> من الوسيط الثاني حيث يكون الشرط صحيحًا ومن الثالث في غير ذلك، صفًا بصف."},{"text":"الصفوف التي تكون فيها الكمية 3 على الأقل","why":"التصفية تتم بـ <code dir=\"ltr\">items[mask]</code>. أما <code dir=\"ltr\">np.where</code> بثلاثة وسائط فتبني قيمًا ولا تحذف صفوفًا."},{"text":"نص واحد، بحسب الصف الأول","why":"إنها تقيّم كل الصفوف، وتعيد تسمية لكل صف."}],"answer":0}],"exercise":{"kind":"python","files":["order_items.csv"],"starter":"import pandas as pd\n\nitems = pd.read_csv(\"order_items.csv\")\n\n# 1. Column \"revenue\": quantity * unit_price * (1 - discount)\n\n# 2. Column \"discount_band\": \"none\" when discount is 0,\n#    \"small\" when it is above 0 and at most 0.10, \"big\" when above 0.10\n\n# 3. Column \"is_bulk\": True when quantity is 4 or more\n\n# 4. Total revenue of all lines, rounded to 2 decimals\ntotal_revenue = None\n","solution":"import pandas as pd\n\nitems = pd.read_csv(\"order_items.csv\")\n\nitems[\"revenue\"] = items[\"quantity\"] * items[\"unit_price\"] * (1 - items[\"discount\"])\n\nitems[\"discount_band\"] = \"none\"\nitems.loc[items[\"discount\"] > 0, \"discount_band\"] = \"small\"\nitems.loc[items[\"discount\"] > 0.10, \"discount_band\"] = \"big\"\n\nitems[\"is_bulk\"] = items[\"quantity\"] >= 4\n\ntotal_revenue = round(items[\"revenue\"].sum(), 2)\nprint(items[\"discount_band\"].value_counts())\n","checks":[{"id":"revenue-col","test":"'revenue' in items.columns and round(float(items.loc[3, 'revenue']), 2) == 270.9"},{"id":"revenue-discounted","test":"round(float(items.loc[items['discount'] == 0.25, 'revenue'].sum()), 2) == round(float((items['quantity'] * items['unit_price'] * 0.75)[items['discount'] == 0.25].sum()), 2)"},{"id":"bands","test":"'discount_band' in items.columns and items['discount_band'].value_counts().to_dict() == {'none': 3367, 'big': 393, 'small': 231}"},{"id":"bulk","test":"'is_bulk' in items.columns and items['is_bulk'].dtype == bool and int(items['is_bulk'].sum()) == 126"},{"id":"total","test":"round(float(total_revenue), 2) == 471940.08"},{"id":"rows-kept","test":"len(items) == 3991"}],"title":"أضِف الإيراد والتسميات إلى بنود الطلبات","prompt":"<p>أضِف ثلاثة أعمدة إلى <code dir=\"ltr\">items</code>: <code dir=\"ltr\">revenue</code> (الكمية × سعر الوحدة × (1 − الخصم))، و<code dir=\"ltr\">discount_band</code> (<code dir=\"ltr\">&quot;none&quot;</code> حين يكون الخصم 0، و<code dir=\"ltr\">&quot;small&quot;</code> حين يكون أكبر من 0 وأقل من أو يساوي 0.10، و<code dir=\"ltr\">&quot;big&quot;</code> حين يكون أكبر من 0.10)، و<code dir=\"ltr\">is_bulk</code> (قيمة منطقية تساوي <code dir=\"ltr\">True</code> حين تكون الكمية 4 أو أكثر). ثم اجعل <code dir=\"ltr\">total_revenue</code> مجموع <code dir=\"ltr\">revenue</code>، مقرّبًا إلى منزلتين عشريتين. احتفظ بكل الصفوف الـ 3,991.</p>\n","hints":["الإسناد إلى اسم عمود جديد، <code dir=\"ltr\">items[&quot;revenue&quot;] = ...</code>، ينشئ العمود لكل الصفوف.","للفئات، اجعل <code dir=\"ltr\">items[&quot;discount_band&quot;] = &quot;none&quot;</code> أولًا، ثم اكتب فوقها بـ <code dir=\"ltr\">items.loc[mask, &quot;discount_band&quot;] = &quot;small&quot;</code> ثم مرة أخرى لـ <code dir=\"ltr\">&quot;big&quot;</code>، الشرط الأوسع أولًا.","المقارنة تعيد أصلًا قيمًا منطقية: <code dir=\"ltr\">items[&quot;is_bulk&quot;] = items[&quot;quantity&quot;] &gt;= 4</code>."],"explanation":"<p>الحساب على الأعمدة يحسب إيراد كل البنود دفعة واحدة، والمجموع 471,940.08 يطابق ما في الدرس. والفئات تتبع نمط القيمة الافتراضية ثم الكتابة فوقها: كل صف يبدأ <code dir=\"ltr\">none</code>، والصفوف المخصومة تصبح <code dir=\"ltr\">small</code>، والصفوف التي يتجاوز خصمها 10% يُكتب فوقها <code dir=\"ltr\">big</code>، فتكون الأعداد 3,367 / 231 / 393. وكانت <code dir=\"ltr\">np.select</code> مع قائمة من الشروط ستعمل أيضًا. أما <code dir=\"ltr\">is_bulk</code> فلا تحتاج <code dir=\"ltr\">np.where</code> إطلاقًا: المقارنة أصلًا عمود منطقي. كل تغيير كان إسنادًا مباشرًا إلى <code dir=\"ltr\">items</code>، وهي الطريقة الآمنة مع Copy-on-Write لتعديل DataFrame.</p>\n","checkLabels":{"revenue-col":"العمود <code dir=\"ltr\">revenue</code> موجود، والبند 4 (الفهرس 3) يساوي 270.90","revenue-discounted":"الخصومات مطبّقة في <code dir=\"ltr\">revenue</code>","bands":"<code dir=\"ltr\">discount_band</code> يقسم البنود إلى 3,367 في <code dir=\"ltr\">none</code> و231 في <code dir=\"ltr\">small</code> و393 في <code dir=\"ltr\">big</code>","bulk":"<code dir=\"ltr\">is_bulk</code> عمود منطقي فيه 126 بندًا بالجملة","total":"<code dir=\"ltr\">total_revenue</code> يساوي 471,940.08","rows-kept":"ما زال في <code dir=\"ltr\">items</code> كل الصفوف الـ 3,991"}},"words":630,"readMinutes":4}