{"id":"l-pda-4-1","courseId":"python-data-analysis","lang":"ar","kind":"lesson","summary":"لخّص البيانات بحسب المجموعة باستخدام groupby، واحسب عدة إحصاءات مسمّاة دفعة واحدة باستخدام agg، واختر بشكل صحيح بين size و count، وبين نتيجة مفهرسة ونتيجة مسطّحة.","html":"<p>“ما متوسط قيمة الطلب لدينا؟” يبدو رقمًا واحدًا، لكن <code dir=\"ltr\">order_items</code> ليس فيه عمود لقيمة الطلب: الطلب الذي فيه أربعة منتجات له أربعة صفوف. تحتاج أولًا صفًا واحدًا لكل طلب، يُجمع فيه إيراد الطلب من بنوده. و&quot;الإيراد لكل منتج&quot; و&quot;الطلبات لكل قناة&quot; و&quot;المبيعات لكل دولة&quot; أسئلة لها الشكل نفسه. في جدول البيانات كنت ستبني جدولًا محوريًا؛ وفي pandas تستخدم التجميع (<code dir=\"ltr\">groupby</code>)، الـ method التي ستستدعيها أكثر من أي method أخرى.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">التقسيم، والتطبيق، وضمّ النتائج</h2>\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\">\"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>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">by_product </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> items.groupby(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"product_id\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"revenue\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].sum()</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(by_product.sort_values(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">ascending</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">False</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\">).round(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">2</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:#0550AE;--shiki-dark:#79C0FF\">round</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(by_product.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\">\"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></code></pre><div class=\"run-output\" data-run-output=\"0\" hidden></div></div>\n<p>اقرأ السطر الأوسط كثلاث خطوات. <strong>قسّم</strong> الصفوف إلى مجموعات، واحدة لكل <code dir=\"ltr\">product_id</code>. <strong>طبّق</strong> حسابًا، <code dir=\"ltr\">sum</code>، على عمود <code dir=\"ltr\">revenue</code> في كل مجموعة. <strong>ضُمّ</strong> النتائج في Series فهرسها مفتاح المجموعة. المنتج 21، Standing Desk، حقّق 60,017.83 دولارًا، أي نحو ضعف المنتج الذي يليه.</p>\n<p>السطر الأخير عادة تستحق أن تنسخها: مجاميع المجموعات تساوي المجموع الكلي. إذا لم تتساوَ، فهناك صفوف ضاعت (مثل الصفوف التي مفتاحها <code dir=\"ltr\">NaN</code>، والتي تُسقطها <code dir=\"ltr\">groupby</code> افتراضيًا) أو تكرّرت قبل أن تجمّع.</p>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 700 240\" role=\"img\" aria-labelledby=\"l-pda-4-1-t1\"><defs><marker id=\"arrow-l-pda-4-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-pda-4-1-t1\">ستة بنود طلبات بمفاتيح A و A و B و A و C و C. يجمعها التقسيم في ثلاثة صناديق بحسب المفتاح. ويجمع التطبيق الإيراد في كل صندوق. ويُنتج الضمّ نتيجة من ثلاثة صفوف: A و B و C مع مجاميعها.</title>\n  <text class=\"d-label-strong\" x=\"80\" y=\"24\" text-anchor=\"middle\">الصفوف</text>\n  <rect class=\"d-box\" x=\"20\" y=\"36\" width=\"120\" height=\"26\" rx=\"5\"/><text class=\"d-code\" x=\"80\" y=\"54\" text-anchor=\"middle\">A  88.20</text>\n  <rect class=\"d-box\" x=\"20\" y=\"66\" width=\"120\" height=\"26\" rx=\"5\"/><text class=\"d-code\" x=\"80\" y=\"84\" text-anchor=\"middle\">A  33.60</text>\n  <rect class=\"d-box\" x=\"20\" y=\"96\" width=\"120\" height=\"26\" rx=\"5\"/><text class=\"d-code\" x=\"80\" y=\"114\" text-anchor=\"middle\">B  19.95</text>\n  <rect class=\"d-box\" x=\"20\" y=\"126\" width=\"120\" height=\"26\" rx=\"5\"/><text class=\"d-code\" x=\"80\" y=\"144\" text-anchor=\"middle\">A 270.90</text>\n  <rect class=\"d-box\" x=\"20\" y=\"156\" width=\"120\" height=\"26\" rx=\"5\"/><text class=\"d-code\" x=\"80\" y=\"174\" text-anchor=\"middle\">C  96.60</text>\n  <rect class=\"d-box\" x=\"20\" y=\"186\" width=\"120\" height=\"26\" rx=\"5\"/><text class=\"d-code\" x=\"80\" y=\"204\" text-anchor=\"middle\">C  96.60</text>\n  <path class=\"d-arrow\" d=\"M150 120 L190 120\" marker-end=\"url(#arrow-l-pda-4-1-1)\"/>\n  <text class=\"d-label-strong\" x=\"290\" y=\"24\" text-anchor=\"middle\">التقسيم</text>\n  <rect class=\"d-box-primary\" x=\"200\" y=\"36\" width=\"180\" height=\"58\" rx=\"8\"/><text class=\"d-label\" x=\"290\" y=\"70\" text-anchor=\"middle\">A: ثلاثة صفوف</text>\n  <rect class=\"d-box-accent\" x=\"200\" y=\"102\" width=\"180\" height=\"40\" rx=\"8\"/><text class=\"d-label\" x=\"290\" y=\"127\" text-anchor=\"middle\">B: صف واحد</text>\n  <rect class=\"d-box-success\" x=\"200\" y=\"150\" width=\"180\" height=\"58\" rx=\"8\"/><text class=\"d-label\" x=\"290\" y=\"184\" text-anchor=\"middle\">C: صفّان</text>\n  <path class=\"d-arrow\" d=\"M390 120 L430 120\" marker-end=\"url(#arrow-l-pda-4-1-1)\"/>\n  <text class=\"d-label-strong\" x=\"490\" y=\"24\" text-anchor=\"middle\">تطبيق sum</text>\n  <text class=\"d-code\" x=\"490\" y=\"70\" text-anchor=\"middle\">392.70</text>\n  <text class=\"d-code\" x=\"490\" y=\"127\" text-anchor=\"middle\">19.95</text>\n  <text class=\"d-code\" x=\"490\" y=\"184\" text-anchor=\"middle\">193.20</text>\n  <path class=\"d-arrow\" d=\"M545 120 L575 120\" marker-end=\"url(#arrow-l-pda-4-1-1)\"/>\n  <text class=\"d-label-strong\" x=\"635\" y=\"24\" text-anchor=\"middle\">الضمّ</text>\n  <rect class=\"d-box\" x=\"585\" y=\"60\" width=\"100\" height=\"120\" rx=\"8\"/>\n  <text class=\"d-code\" x=\"635\" y=\"92\" text-anchor=\"middle\">A 392.70</text>\n  <text class=\"d-code\" x=\"635\" y=\"124\" text-anchor=\"middle\">B  19.95</text>\n  <text class=\"d-code\" x=\"635\" y=\"156\" text-anchor=\"middle\">C 193.20</text>\n</svg><figcaption>تقسم groupby الصفوف بحسب المفتاح، وتطبّق دالة على كل مجموعة، وتضمّ النتائج</figcaption></figure>\n<h2 id=\"sec-2\" tabindex=\"-1\">عدة إحصاءات دفعة واحدة: الحسابات التجميعية المسمّاة</h2>\n<p>رقم واحد لكل مجموعة نادرًا ما يكفي. تحسب <code dir=\"ltr\">agg</code> مع <strong>الحسابات التجميعية المسمّاة (named aggregation)</strong> عدة أرقام، وتسمّي كل عمود ناتج:</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\"> 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>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">per_order </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> items.groupby(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"order_id\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">).agg(</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">    revenue</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</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\">\"sum\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">),</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">    lines</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"order_item_id\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"count\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">),</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">    units</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"quantity\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"sum\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">),</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">    max_discount</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</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:#0A3069;--shiki-dark:#A5D6FF\">\"max\"</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\">(per_order.head().round(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">2</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\">(per_order.shape, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"| average order value:\"</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\">(per_order[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"revenue\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].mean(), </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=\"1\" hidden></div></div>\n<p>كل كلمة مفتاحية عمود ناتج، وكل قيمة زوج: (عمود المُدخل، الدالة). تُعطى الدوال بأسمائها كنصوص: <code dir=\"ltr\">&quot;sum&quot;</code> و<code dir=\"ltr\">&quot;mean&quot;</code> و<code dir=\"ltr\">&quot;median&quot;</code> و<code dir=\"ltr\">&quot;min&quot;</code> و<code dir=\"ltr\">&quot;max&quot;</code> و<code dir=\"ltr\">&quot;count&quot;</code> و<code dir=\"ltr\">&quot;size&quot;</code> و<code dir=\"ltr\">&quot;nunique&quot;</code> و<code dir=\"ltr\">&quot;first&quot;</code> و<code dir=\"ltr\">&quot;last&quot;</code> و<code dir=\"ltr\">&quot;std&quot;</code>. للنتيجة صف لكل طلب، 2,066 صفًا، ومتوسط قيمة الطلب (AOV) هو 228.43 دولارًا، عبر كل الحالات، والإلغاءات منها، حتى الآن.</p>\n<p>سترى أيضًا الأسلوب الأقدم <code dir=\"ltr\">agg({&quot;revenue&quot;: &quot;sum&quot;, &quot;discount&quot;: &quot;max&quot;})</code>، أو <code dir=\"ltr\">agg([&quot;sum&quot;, &quot;mean&quot;])</code> على عمود واحد. إنهما يعملان، لكنهما يعيدان استخدام أسماء المُدخلات، فينتهي جدول فيه إحصاءان للعمود نفسه بعناوين مربكة. أما الحسابات التجميعية المسمّاة فتقول بالضبط ما هو كل عمود.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">الفرق بين size و count</h2>\n<p>طريقتان للعدّ، وتجيبان عن سؤالين مختلفين:</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\"> 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:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(orders.groupby(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"channel\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">).size())                   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># rows per group</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(orders.groupby(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"channel\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"coupon_code\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].count())   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># non-missing coupons per group</span></span></code></pre><div class=\"run-output\" data-run-output=\"2\" hidden></div></div>\n<p>تعدّ <code dir=\"ltr\">size()</code> الصفوف: 1,146 طلب ويب. وتعدّ <code dir=\"ltr\">count()</code> القيم غير المفقودة في عمود: 208 من طلبات الويب تلك فيها كود كوبون. استخدم <code dir=\"ltr\">size</code> (أو <code dir=\"ltr\">count</code> على عمود لا يُفقد أبدًا، مثل المعرّف) لسؤال “كم عددها”، و<code dir=\"ltr\">count</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\">order_items</code> باستخدام <code dir=\"ltr\">size()</code> تعدّ <strong>البنود</strong> لا الطلبات: الطلب الذي فيه أربعة منتجات يُعدّ أربع مرات. إما أن تجمّع جدولًا فيه صف واحد لكل طلب، وإما أن تعدّ المعرّفات المختلفة بـ <code dir=\"ltr\">(&quot;order_id&quot;, &quot;nunique&quot;)</code>. قبل أن تجمّع، قل ماذا يمثّل الصف الواحد.</p>\n</aside>\n<h2 id=\"sec-4\" tabindex=\"-1\">عدة مفاتيح ونتائج مسطّحة</h2>\n<p>جمّع بقائمة أعمدة لتقاطع بُعدين. للنتيجة فهرس من مستويين (<strong>MultiIndex</strong>)، وتنشر <code dir=\"ltr\">unstack()</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\">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\">by_channel_status </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> orders.groupby([</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"channel\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"status\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]).size()</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(by_channel_status.head(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">4</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\">(by_channel_status.unstack())</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">flat </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> orders.groupby(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"channel\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#953800;--shiki-dark:#FFA657\">as_index</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">False</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">).agg(</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">    orders</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"order_id\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"count\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">),</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">    avg_fee</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"shipping_fee\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"mean\"</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\">(flat.round(</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=\"3\" hidden></div></div>\n<p>تُبقي <code dir=\"ltr\">as_index=False</code> مفاتيح المجموعات أعمدة عادية بدلًا من نقلها إلى الفهرس، وهذا مفيد حين تغذّي النتيجة عملية دمج أو رسمًا بيانيًا أو تصدير CSV. وتفعل <code dir=\"ltr\">reset_index()</code> الشيء نفسه لاحقًا على نتيجة مفهرسة.</p>\n<h2 id=\"sec-5\" tabindex=\"-1\">نتائج المجموعة على كل صف: transform</h2>\n<p>أحيانًا تريد رقم المجموعة بجانب كل صف بدلًا من صف لكل مجموعة. سؤال “ما الحصة التي يمثّلها كل بند من طلبه؟” يحتاج أن يعرف كل بند مجموع طلبه. تجري <code dir=\"ltr\">transform</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\">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\">\"order_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.groupby(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"order_id\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"revenue\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">].transform(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"sum\"</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\">\"share_of_order\"</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 style=\"color:#CF222E;--shiki-dark:#FF7B72\">/</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> items[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"order_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[[</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"order_id\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </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\">\"order_revenue\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"share_of_order\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]].head(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">5</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">).round(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">3</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>للطلب 1001 أربعة بنود، وبند Burr Coffee Grinder يحمل 62% من قيمته. القاعدة العملية: <code dir=\"ltr\">agg</code> حين تريد جدول ملخّص، و<code dir=\"ltr\">transform</code> حين تريد عمودًا جديدًا في الجدول التفصيلي.</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>تجميع عمود من نوع category</span></p>\n<p>إذا حوّلت عمودًا إلى <code dir=\"ltr\">category</code> (الدرس 3.2)، فمرّر <code dir=\"ltr\">observed=True</code> إلى <code dir=\"ltr\">groupby</code>. إنها تحتفظ فقط بالفئات التي تظهر فعلًا، وتُسكت التحذير الذي تطبعه pandas 2 عن تغيّر القيمة الافتراضية.</p>\n</aside>\n<p>يبني التمرين جدول “صف لكل طلب” الذي ستستخدمه من الآن فصاعدًا. وفي الدرس التالي تدمجه مع <code dir=\"ltr\">orders</code> و<code dir=\"ltr\">customers</code>، لأن الأسئلة المهمة، مثل “الإيراد بحسب الدولة، دون الإلغاءات”، تحتاج أعمدة من أكثر من جدول.</p>\n","toc":[{"id":"sec-1","text":"التقسيم، والتطبيق، وضمّ النتائج","level":2},{"id":"sec-2","text":"عدة إحصاءات دفعة واحدة: الحسابات التجميعية المسمّاة","level":2},{"id":"sec-3","text":"الفرق بين size و count","level":2},{"id":"sec-4","text":"عدة مفاتيح ونتائج مسطّحة","level":2},{"id":"sec-5","text":"نتائج المجموعة على كل صف: transform","level":2}],"takeaways":["يقسم التجميع (<code dir=\"ltr\">groupby</code>) الصفوف إلى مجموعات بحسب مفتاح، ويطبّق حسابًا على كل مجموعة، ويضمّ النتائج في جدول واحد.","الحسابات التجميعية المسمّاة، <code dir=\"ltr\">agg(revenue=(&quot;revenue&quot;, &quot;sum&quot;), lines=(&quot;order_item_id&quot;, &quot;count&quot;))</code>، تمنح كل عمود ناتج اسمًا واضحًا.","<code dir=\"ltr\">size()</code> تعدّ الصفوف في كل مجموعة؛ و<code dir=\"ltr\">count()</code> تعدّ القيم غير المفقودة في عمود، فيختلفان حين يكون في العمود فجوات.","التجميع بعدة مفاتيح يعطيك MultiIndex؛ و<code dir=\"ltr\">as_index=False</code> أو <code dir=\"ltr\">reset_index()</code> تعيدان المفاتيح أعمدة عادية.","تحقّق من أن نتائج المجموعات تعود فتساوي المجموع الكلي، كي تعرف أنه لم يضِع صف ولم يُحسب مرتين."],"further":[{"title":"Group by: split-apply-combine","url":"https://pandas.pydata.org/docs/user_guide/groupby.html"},{"title":"pandas.core.groupby.DataFrameGroupBy.agg","url":"https://pandas.pydata.org/docs/reference/api/pandas.core.groupby.DataFrameGroupBy.agg.html"}],"quiz":[{"q":"<p>تعطي <code dir=\"ltr\">orders.groupby(&quot;channel&quot;)[&quot;coupon_code&quot;].count()</code> القيمة 208 للويب، لكن <code dir=\"ltr\">orders.groupby(&quot;channel&quot;).size()</code> تعطي 1,146. لماذا؟</p>","options":[{"text":"إحداهما تستبعد الطلبات الملغاة.","why":"لا يصفّي أيٌّ من الاستدعاءين بحسب الحالة؛ كلاهما يرى كل الصفوف."},{"text":"<code dir=\"ltr\">count()</code> تعدّ أكواد الكوبونات غير المفقودة فقط، بينما تعدّ <code dir=\"ltr\">size()</code> كل صف في المجموعة.","why":"صحيح. 208 طلبات ويب استخدمت كوبونًا؛ و1,146 طلب ويب موجود. استخدم <code dir=\"ltr\">size()</code> لعدّ الصفوف و<code dir=\"ltr\">count()</code> لعدّ القيم الموجودة."},{"text":"<code dir=\"ltr\">count()</code> تعدّ أكواد الكوبونات المختلفة.","why":"القيم المختلفة تعدّها <code dir=\"ltr\">nunique()</code>. أما <code dir=\"ltr\">count()</code> فتعدّ كل قيمة غير مفقودة، والمكرّرة منها."},{"text":"<code dir=\"ltr\">size()</code> تحسب الطلبات التي فيها عدة عناصر مرتين.","why":"في <code dir=\"ltr\">orders</code> صف واحد لكل طلب، فلا يوجد ما يُحسب مرتين."}],"answer":1},{"q":"<p>أيّ استدعاء يعيد صفًا لكل طلب بعمودين اسمهما <code dir=\"ltr\">revenue</code> و<code dir=\"ltr\">lines</code>؟</p>","options":[{"text":"<code dir=\"ltr\">items.groupby(&quot;order_id&quot;).agg(revenue=(&quot;revenue&quot;, &quot;sum&quot;), lines=(&quot;order_item_id&quot;, &quot;count&quot;))</code>","why":"صحيح. كل كلمة مفتاحية تصبح عمودًا ناتجًا، معرَّفًا بزوج (عمود، دالة)."},{"text":"<code dir=\"ltr\">items.groupby(&quot;order_id&quot;)[&quot;revenue&quot;, &quot;order_item_id&quot;].sum()</code>","why":"اختيار عدة أعمدة يحتاج قائمة (أقواس مزدوجة)، وحتى عندها تحصل على مجموعين بالأسماء الأصلية، لا على عدد."},{"text":"<code dir=\"ltr\">items.agg(revenue=(&quot;revenue&quot;, &quot;sum&quot;), lines=(&quot;order_item_id&quot;, &quot;count&quot;))</code>","why":"بدون <code dir=\"ltr\">groupby</code> يجمّع هذا الجدول كله في مجاميع مفردة، لا صفًا لكل طلب."}],"answer":0},{"q":"<p>جمّعت <code dir=\"ltr\">items</code> بحسب الطلب وجمعت الإيراد، ثم جمعت تلك النتيجة. المجموع الكلي أعلى بنسبة 3% من <code dir=\"ltr\">items[&quot;revenue&quot;].sum()</code>. ما التفسير الأرجح؟</p>","options":[{"text":"الـ groupby تقرّب القيم إلى الأعلى دائمًا.","why":"لا تقرّب الـ groupby شيئًا؛ مجاميع المجموعات تساوي المجموع الكلي تمامًا، باستثناء ضوضاء الأعداد العشرية."},{"text":"أسقطت الـ groupby الطلبات ذات المفاتيح المفقودة.","why":"إسقاط الصفوف ذات المفاتيح المفقودة سيجعل المجموع المجمَّع أقل لا أعلى."},{"text":"خطأ في حساب الأعداد العشرية.","why":"خطأ الأعداد العشرية يكون نحو المنزلة العشرية الثانية عشرة، ولا يصل أبدًا إلى 3%."},{"text":"الجدول الذي جمّعته ليس الجدول الذي تظنه؛ مثلًا، رُبط بجدول آخر كرّر الصفوف.","why":"صحيح. التجميع لا يخترع أموالًا، فالمجموع الأعلى يعني أن المُدخل فيه صفوف زائدة. يبيّن الدرس 4.2 كيف تسبّب عمليات الدمج هذا بالضبط."}],"answer":3}],"exercise":{"kind":"python","files":["order_items.csv"],"starter":"import pandas as pd\n\nitems = pd.read_csv(\"order_items.csv\")\nitems[\"revenue\"] = items[\"quantity\"] * items[\"unit_price\"] * (1 - items[\"discount\"])\n\n# 1. One row per order_id with columns: revenue (sum), lines (number of rows), units (sum of quantity)\nper_order = None\n\n# 2. Average order value (mean revenue per order), rounded to 2 decimals\navg_order_value = None\n\n# 3. Share of orders with 2 or more lines, rounded to 3 decimals\nmulti_line_share = None\n\n# 4. product_id with the highest total revenue\ntop_product = None\n","solution":"import pandas as pd\n\nitems = pd.read_csv(\"order_items.csv\")\nitems[\"revenue\"] = items[\"quantity\"] * items[\"unit_price\"] * (1 - items[\"discount\"])\n\nper_order = items.groupby(\"order_id\").agg(\n    revenue=(\"revenue\", \"sum\"),\n    lines=(\"order_item_id\", \"count\"),\n    units=(\"quantity\", \"sum\"),\n)\n\navg_order_value = round(per_order[\"revenue\"].mean(), 2)\nmulti_line_share = round((per_order[\"lines\"] >= 2).mean(), 3)\ntop_product = items.groupby(\"product_id\")[\"revenue\"].sum().idxmax()\nprint(per_order.head())\n","checks":[{"id":"shape","test":"isinstance(per_order, pd.DataFrame) and len(per_order) == 2066 and {'revenue', 'lines', 'units'} <= set(per_order.columns)"},{"id":"order-1001","test":"(per_order.loc[1001, 'revenue'] if 1001 in per_order.index else per_order.set_index('order_id').loc[1001, 'revenue']).round(2) == 438.9"},{"id":"lines-units","test":"int(per_order['lines'].sum()) == 3991 and int(per_order['units'].sum()) == int(items['quantity'].sum())"},{"id":"aov","test":"round(float(avg_order_value), 2) == 228.43"},{"id":"multi","test":"round(float(multi_line_share), 3) == 0.551"},{"id":"top","test":"int(top_product) == 21"}],"title":"ابنِ جدول \"صف لكل طلب\"","prompt":"<p>باستخدام <code dir=\"ltr\">items</code> (مع إضافة عمود الإيراد مسبقًا)، ابنِ <code dir=\"ltr\">per_order</code>: صف لكل <code dir=\"ltr\">order_id</code> بالأعمدة <code dir=\"ltr\">revenue</code> (المجموع) و<code dir=\"ltr\">lines</code> (عدد بنود الطلب) و<code dir=\"ltr\">units</code> (مجموع <code dir=\"ltr\">quantity</code>). ثم اجعل <code dir=\"ltr\">avg_order_value</code> متوسط إيراد الطلب مقرّبًا إلى منزلتين عشريتين، و<code dir=\"ltr\">multi_line_share</code> حصة الطلبات التي فيها بندان أو أكثر مقرّبة إلى 3 منازل عشرية، و<code dir=\"ltr\">top_product</code> قيمة <code dir=\"ltr\">product_id</code> صاحب أعلى إيراد إجمالي.</p>\n","hints":["<code dir=\"ltr\">items.groupby(&quot;order_id&quot;).agg(revenue=(&quot;revenue&quot;, &quot;sum&quot;), ...)</code> مع كلمة مفتاحية لكل عمود ناتج.","عُدّ البنود بـ <code dir=\"ltr\">(&quot;order_item_id&quot;, &quot;count&quot;)</code> أو <code dir=\"ltr\">(&quot;order_id&quot;, &quot;size&quot;)</code>. والحصة هي متوسط قيمة منطقية: <code dir=\"ltr\">(per_order[&quot;lines&quot;] &gt;= 2).mean()</code>.","<code dir=\"ltr\">items.groupby(&quot;product_id&quot;)[&quot;revenue&quot;].sum().idxmax()</code> تعيد تسمية أكبر مجموعة."],"explanation":"<p>تحوّل الحسابات التجميعية المسمّاة 3,991 بندًا إلى 2,066 طلبًا في استدعاء واحد، بأسماء أعمدة مقروءة. وتؤكّد الفحوص أن الأجزاء تساوي الكل: عمود <code dir=\"ltr\">lines</code> يعود مجموعه إلى 3,991، والوحدات إلى إجمالي الكمية، فلم يضِع بند ولم يُحسب مرتين. متوسط قيمة الطلب (AOV) هو 228.43 دولارًا، و55.1% من الطلبات تحتوي أكثر من منتج، وهذه حقيقة مفيدة حين يقترح أحدهم عرضًا ترويجيًا على المنتجات المفردة. المنتج 21، Standing Desk 140cm، هو الأعلى إيرادًا. وستُقبل <code dir=\"ltr\">as_index=False</code> أيضًا: عندها يكون <code dir=\"ltr\">order_id</code> عمودًا بدلًا من الفهرس.</p>\n","checkLabels":{"shape":"في <code dir=\"ltr\">per_order</code> 2,066 صفًا والأعمدة revenue و lines و units","order-1001":"إيراد الطلب 1001 يساوي 438.90","lines-units":"البنود والوحدات تعود فتساوي مجاميع جدول البنود","aov":"<code dir=\"ltr\">avg_order_value</code> يساوي 228.43","multi":"<code dir=\"ltr\">multi_line_share</code> يساوي 0.551","top":"<code dir=\"ltr\">top_product</code> يساوي 21"}},"words":599,"readMinutes":4}