{"id":"l-pda-2-5","courseId":"python-data-analysis","lang":"en","kind":"lesson","summary":"Create calculated columns with vectorised arithmetic, build conditional columns with .loc and np.where, map codes to labels, and change values safely under pandas Copy-on-Write rules.","html":"<p>Cartwheel’s <code dir=\"ltr\">order_items</code> table has a quantity, a unit price and a discount on each of its 3,991 lines, but no revenue. Revenue is something you calculate, and how you calculate it has to be written down where everyone can see it. That is what a computed column does: it turns a business rule into one line of code applied to every row.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">Calculated columns</h2>\n<p>Assigning to a new column name creates it:</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=\"Run this example\"><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>Run</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><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>Copy</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>Each line works on whole columns, row by row, with no loop. The result: 471,940.08 dollars of revenue across all lines, after 11,658.52 dollars of discounts. (That total still includes cancelled orders; you will remove them in Section 4 once you can join <code dir=\"ltr\">order_items</code> to <code dir=\"ltr\">orders</code>.)</p>\n<p><code dir=\"ltr\">assign()</code> does the same but returns a new DataFrame instead of changing the existing one, which lets you chain steps:</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=\"Run this example\"><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>Run</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><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>Copy</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> is a tiny unnamed function that receives the DataFrame at that point in the chain. You need it when a step uses a column created earlier in the same chain. Both styles are fine; plain assignment is easier to read when you are starting out, and chains shine in the cleaning function you will write in Lesson 3.5.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">Conditional columns</h2>\n<p>A two-way label is a job for NumPy’s <code dir=\"ltr\">where</code>, which pandas is built on:</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=\"Run this example\"><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>Run</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><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>Copy</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>Read it as “where revenue is at least 100, <code dir=\"ltr\">large</code>; elsewhere, <code dir=\"ltr\">small</code>”. For three or more categories, start with a default and overwrite subsets with <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=\"Run this example\"><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>Run</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><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>Copy</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>Order matters exactly as it did with <code dir=\"ltr\">if</code>/<code dir=\"ltr\">elif</code> in Lesson 1.4, but reversed: later assignments overwrite earlier ones, so go from the broadest condition to the narrowest. Discounts of 5% and 10% end up <code dir=\"ltr\">small</code>; 15% and 25% end up <code dir=\"ltr\">big</code>.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">Translating codes with map</h2>\n<p>Columns full of codes (<code dir=\"ltr\">mobile_app</code>, ids, status flags) often need readable labels. <code dir=\"ltr\">map()</code> with a dictionary translates each value:</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=\"Run this example\"><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>Run</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><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>Copy</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>Any value missing from the dictionary becomes <code dir=\"ltr\">NaN</code>, silently. The last line is the check that catches it: zero unmapped values means every channel had a label.</p>\n<h2 id=\"sec-4\" tabindex=\"-1\">Fixing a column’s type with astype</h2>\n<p>Sometimes the values are right but the type is not. <code dir=\"ltr\">products.csv</code> stores <code dir=\"ltr\">is_active</code> as 0 and 1, which pandas reads as integers. Summing works, but a reader of your code cannot tell a flag from a count, and filters read awkwardly. <code dir=\"ltr\">astype()</code> converts a whole column:</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=\"Run this example\"><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>Run</span></button><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><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>Copy</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>Three products are discontinued, and <code dir=\"ltr\">~products[&quot;is_active&quot;]</code> reads as “not active”. Use <code dir=\"ltr\">astype</code> when every value can be converted cleanly; Section 3 shows what to do when some cannot, such as totals with dollar signs.</p>\n<h2 id=\"sec-5\" tabindex=\"-1\">Changing values: the one rule</h2>\n<p>Here is the rule that saves you hours of confusion: <strong>to change values in a DataFrame, assign to it in a single step</strong>, with a new column or with <code dir=\"ltr\">.loc[rows, column]</code>. Never select and then assign in two steps:</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=\"Copy code\"><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>Copy</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>The first form selects the <code dir=\"ltr\">discount</code> column, which produces a new object, and then assigns into that object. Whether <code dir=\"ltr\">items</code> itself changed used to depend on pandas internals, and pandas 2 prints a <code dir=\"ltr\">ChainedAssignmentError</code> warning or a <code dir=\"ltr\">SettingWithCopyWarning</code> when it spots the pattern. With <strong>Copy-on-Write</strong> (the default from pandas 3.0, available in pandas 2 through <code dir=\"ltr\">pd.options.mode.copy_on_write = True</code>), the rule becomes simple and strict: every selection behaves like a copy, so chained assignment never updates the original. Write it the <code dir=\"ltr\">.loc</code> way and your code behaves identically on every version.</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\">Common mistake</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Editing a filtered table and expecting the original to change</span></p>\n<p><code dir=\"ltr\">q4 = orders[in_q4]</code> followed by <code dir=\"ltr\">q4[&quot;label&quot;] = &quot;Q4&quot;</code> adds the column to <code dir=\"ltr\">q4</code> only. That is correct behaviour, not a bug: a filtered table is its own table. On pandas 2 without Copy-on-Write (the version this course runs) the second line also prints a <code dir=\"ltr\">SettingWithCopyWarning</code>, because pandas cannot tell which table you meant to change; <code dir=\"ltr\">q4 = orders[in_q4].copy()</code> states that you want a separate table and silences it. If you meant to label rows inside <code dir=\"ltr\">orders</code>, write <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\">Tip</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Removing and renaming</span></p>\n<p><code dir=\"ltr\">df.drop(columns=[&quot;gross&quot;])</code> removes columns and <code dir=\"ltr\">df.rename(columns={&quot;unit_price&quot;: &quot;price&quot;})</code> renames them. Both return a new DataFrame, so assign the result: <code dir=\"ltr\">items = items.drop(columns=[&quot;gross&quot;])</code>. Forgetting that assignment is the most common reason a column you dropped seems to come back.</p>\n</aside>\n<p>That completes your pandas foundations: load, inspect, select, filter, sort and compute. Section 3 points these tools at the messy export, where blanks, typos, money strings and ambiguous dates are waiting.</p>\n","toc":[{"id":"sec-1","text":"Calculated columns","level":2},{"id":"sec-2","text":"Conditional columns","level":2},{"id":"sec-3","text":"Translating codes with map","level":2},{"id":"sec-4","text":"Fixing a column’s type with astype","level":2},{"id":"sec-5","text":"Changing values: the one rule","level":2}],"takeaways":["<code dir=\"ltr\">df[&quot;new&quot;] = expression</code> adds a column computed for every row at once; <code dir=\"ltr\">assign()</code> does the same and returns a new DataFrame.","Change existing values with one <code dir=\"ltr\">.loc[row_mask, &quot;col&quot;] = value</code> call, never with chained brackets like <code dir=\"ltr\">df[&quot;col&quot;][mask] = value</code>.","<code dir=\"ltr\">np.where(condition, a, b)</code> builds a two-way column; <code dir=\"ltr\">.loc</code> assignments in sequence or <code dir=\"ltr\">np.select</code> handle more categories.","<code dir=\"ltr\">map()</code> with a dictionary translates codes into labels, and values missing from the dictionary become <code dir=\"ltr\">NaN</code>.","Under Copy-on-Write, every selection behaves like a copy, so the only way to change a DataFrame is to assign to it directly."],"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>You want to cap every discount above 0.2 at 0.2. Which line does it correctly in pandas 2 and 3?</p>","options":[{"text":"<code dir=\"ltr\">items[&quot;discount&quot;][items[&quot;discount&quot;] &gt; 0.2] = 0.2</code>","why":"This is chained assignment. It selects a column first and then assigns into that intermediate object; under Copy-on-Write the original table never changes."},{"text":"<code dir=\"ltr\">items[items[&quot;discount&quot;] &gt; 0.2][&quot;discount&quot;] = 0.2</code>","why":"Also chained. The filter creates a new table, the assignment changes that temporary table, and <code dir=\"ltr\">items</code> is left as it was."},{"text":"<code dir=\"ltr\">items.loc[items[&quot;discount&quot;] &gt; 0.2, &quot;discount&quot;] = 0.2</code>","why":"Correct. One <code dir=\"ltr\">.loc</code> call names the rows and the column, so pandas assigns directly into <code dir=\"ltr\">items</code>."},{"text":"<code dir=\"ltr\">items[&quot;discount&quot;] == 0.2</code>","why":"This compares and returns a boolean Series; <code dir=\"ltr\">==</code> never assigns."}],"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>. What happens to marketplace orders?</p>","options":[{"text":"They keep the value <code dir=\"ltr\">&quot;marketplace&quot;</code>.","why":"<code dir=\"ltr\">map</code> replaces every value; anything not found in the dictionary does not pass through unchanged."},{"text":"Their label becomes <code dir=\"ltr\">NaN</code>.","why":"Correct. Values missing from the mapping dictionary become missing. Check <code dir=\"ltr\">channel_label.isna().sum()</code> after every <code dir=\"ltr\">map</code>."},{"text":"pandas raises a <code dir=\"ltr\">KeyError</code>.","why":"<code dir=\"ltr\">map</code> with a dictionary never raises for unknown values; it fills them with <code dir=\"ltr\">NaN</code>, which is exactly why it is easy to miss."}],"answer":1},{"q":"<p>What does <code dir=\"ltr\">np.where(items[&quot;quantity&quot;] &gt;= 3, &quot;bulk&quot;, &quot;regular&quot;)</code> produce?</p>","options":[{"text":"An array with <code dir=\"ltr\">&quot;bulk&quot;</code> or <code dir=\"ltr\">&quot;regular&quot;</code> for every row, which you can assign as a new column","why":"Correct. <code dir=\"ltr\">np.where</code> picks from the second argument where the condition is true and from the third elsewhere, row by row."},{"text":"The rows where quantity is at least 3","why":"Filtering is done with <code dir=\"ltr\">items[mask]</code>. <code dir=\"ltr\">np.where</code> with three arguments builds values, it does not drop rows."},{"text":"A single string, depending on the first row","why":"It evaluates every row, returning one label per row."}],"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":"Add revenue and labels to order lines","prompt":"<p>Add three columns to <code dir=\"ltr\">items</code>: <code dir=\"ltr\">revenue</code> (quantity × unit price × (1 − discount)), <code dir=\"ltr\">discount_band</code> (<code dir=\"ltr\">&quot;none&quot;</code> when the discount is 0, <code dir=\"ltr\">&quot;small&quot;</code> when it is above 0 and at most 0.10, <code dir=\"ltr\">&quot;big&quot;</code> when it is above 0.10), and <code dir=\"ltr\">is_bulk</code> (a boolean, <code dir=\"ltr\">True</code> when quantity is 4 or more). Then set <code dir=\"ltr\">total_revenue</code> to the sum of <code dir=\"ltr\">revenue</code>, rounded to 2 decimals. Keep all 3,991 rows.</p>\n","hints":["Assigning to a new column name, <code dir=\"ltr\">items[&quot;revenue&quot;] = ...</code>, creates the column for every row.","For the bands, set <code dir=\"ltr\">items[&quot;discount_band&quot;] = &quot;none&quot;</code> first, then overwrite with <code dir=\"ltr\">items.loc[mask, &quot;discount_band&quot;] = &quot;small&quot;</code> and again for <code dir=\"ltr\">&quot;big&quot;</code>, broadest condition first.","A comparison already returns booleans: <code dir=\"ltr\">items[&quot;is_bulk&quot;] = items[&quot;quantity&quot;] &gt;= 4</code>."],"explanation":"<p>Column arithmetic computes every line’s revenue at once, and the total, 471,940.08, matches the lesson. The bands follow the default-then-overwrite pattern: every row starts as <code dir=\"ltr\">none</code>, discounted rows become <code dir=\"ltr\">small</code>, and rows above 10% are overwritten to <code dir=\"ltr\">big</code>, giving 3,367 / 231 / 393. <code dir=\"ltr\">np.select</code> with a list of conditions would also work. <code dir=\"ltr\">is_bulk</code> needs no <code dir=\"ltr\">np.where</code> at all: a comparison is already a boolean column. Every change was a direct assignment to <code dir=\"ltr\">items</code>, which is the Copy-on-Write-safe way to modify a DataFrame.</p>\n","checkLabels":{"revenue-col":"<code dir=\"ltr\">revenue</code> exists and line 4 (index 3) is 270.90","revenue-discounted":"Discounts are applied in <code dir=\"ltr\">revenue</code>","bands":"<code dir=\"ltr\">discount_band</code> splits lines into none 3,367 / small 231 / big 393","bulk":"<code dir=\"ltr\">is_bulk</code> is a boolean column with 126 bulk lines","total":"<code dir=\"ltr\">total_revenue</code> is 471,940.08","rows-kept":"<code dir=\"ltr\">items</code> still has all 3,991 rows"}},"words":735,"readMinutes":4}