{"id":"l-pda-2-3","courseId":"python-data-analysis","lang":"en","kind":"lesson","summary":"Select columns with square brackets, then pick exact rows and columns with .loc (by label) and .iloc (by position), and know which one to use after sorting or filtering.","html":"<p>Cartwheel’s product manager asks: “What do we charge for the coffee grinder, product 7?” and “Show me the five priciest products with their costs.” Both are selection problems: out of a table, get exactly these rows and these columns. pandas gives you two precise tools for that, <code dir=\"ltr\">.loc</code> and <code dir=\"ltr\">.iloc</code>, and most beginner confusion comes from mixing them up. The rule is short: <code dir=\"ltr\">.loc</code> uses <strong>labels</strong>, <code dir=\"ltr\">.iloc</code> uses <strong>positions</strong>.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">Columns first</h2>\n<p>Square brackets on a DataFrame select columns:</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\">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 style=\"color:#953800;--shiki-dark:#FFA657\">index_col</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"product_id\"</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\">\"name\"</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 style=\"color:#6E7781;--shiki-dark:#8B949E\"># one column: a Series</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\">\"name\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"unit_price\"</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 style=\"color:#6E7781;--shiki-dark:#8B949E\"># a list of columns: a DataFrame</span></span></code></pre><div class=\"run-output\" data-run-output=\"0\" hidden></div></div>\n<p><code dir=\"ltr\">index_col=&quot;product_id&quot;</code> made the product id the row index instead of the default 0, 1, 2. That single choice makes everything below read naturally: product 7 is the row labelled 7. On an already-loaded DataFrame, <code dir=\"ltr\">products.set_index(&quot;product_id&quot;)</code> does the same thing and returns a new DataFrame.</p>\n<p>You will also see <code dir=\"ltr\">products.unit_price</code> in tutorials. Dot access works for simple names, but it fails for names with spaces, and it quietly returns the wrong thing when a column shares its name with a DataFrame method: a column called <code dir=\"ltr\">count</code> or <code dir=\"ltr\">size</code> is shadowed by the method of the same name. Square brackets always work, so make them your default.</p>\n<p>The double brackets are not a typo. The outer pair is the selection; the inner pair is a Python list of column names. One column in a list still gives a DataFrame.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">.loc: select by label</h2>\n<p><code dir=\"ltr\">.loc[rows, columns]</code> takes row labels first, then column labels:</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\">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 style=\"color:#953800;--shiki-dark:#FFA657\">index_col</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"product_id\"</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:#0550AE;--shiki-dark:#79C0FF\">7</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"unit_price\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">])                       </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># one value</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:#0550AE;--shiki-dark:#79C0FF\">7</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">])                                     </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># one row, as a Series</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:#0550AE;--shiki-dark:#79C0FF\">11</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">21</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">37</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\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"unit_price\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]])  </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># chosen rows and columns</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:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"name\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">:</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"unit_price\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">])              </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># label slices</span></span></code></pre><div class=\"run-output\" data-run-output=\"1\" hidden></div></div>\n<p>Lists pick exactly the labels you name, in that order. Slices take a range of labels, and here is the part to remember: <strong><code dir=\"ltr\">.loc</code> slices include the end label</strong>. <code dir=\"ltr\">products.loc[1:3]</code> returns products 1, 2 and 3. The column slice <code dir=\"ltr\">&quot;name&quot;:&quot;unit_price&quot;</code> likewise includes <code dir=\"ltr\">unit_price</code>. It makes sense once you think in labels: “from product 1 to product 3” includes product 3.</p>\n<p>Ask for a label that does not exist, say <code dir=\"ltr\">products.loc[99]</code>, and you get <code dir=\"ltr\">KeyError: 99</code>. That is a feature: a wrong id should fail loudly, not return an empty result you might paste into a report. When a missing label is a normal possibility, test first with <code dir=\"ltr\">99 in products.index</code>, which returns <code dir=\"ltr\">True</code> or <code dir=\"ltr\">False</code>.</p>\n<p><code dir=\"ltr\">.loc</code> is also the one tool you use for <strong>assigning</strong> values, as you will see in Lesson 2.5: <code dir=\"ltr\">products.loc[7, &quot;unit_price&quot;] = 135.45</code> changes exactly one cell.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">.iloc: select by position</h2>\n<p><code dir=\"ltr\">.iloc</code> ignores labels and counts positions from 0, with slices that exclude the end, exactly like Python lists:</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\"> 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 style=\"color:#953800;--shiki-dark:#FFA657\">index_col</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"product_id\"</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.iloc[</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">])            </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># first row, whatever its label</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(products.iloc[:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, :</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">2</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">])       </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># first three rows, first two columns</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(products.iloc[</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</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\">])   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># last row's name</span></span></code></pre><div class=\"run-output\" data-run-output=\"2\" hidden></div></div>\n<p>Use <code dir=\"ltr\">.iloc</code> when position is what you mean: “the first five”, “the last row”, “every other row”. Use <code dir=\"ltr\">.loc</code> when identity is what you mean: “product 7”, “the <code dir=\"ltr\">unit_price</code> column”.</p>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 700 250\" role=\"img\" aria-labelledby=\"l-pda-2-3-t1\"><defs><marker id=\"arrow-l-pda-2-3-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-2-3-t1\">A table sorted by price with index labels 21, 22, 41, 1 in that order and positions 0 to 3. loc[1] points to the row labelled 1, which sits at position 3. iloc[0] points to the row at position 0, which is labelled 21.</title>\n  <text class=\"d-label-muted\" x=\"40\" y=\"30\" text-anchor=\"middle\">position</text>\n  <text class=\"d-label-muted\" x=\"120\" y=\"30\" text-anchor=\"middle\">label</text>\n  <text class=\"d-label-strong\" x=\"300\" y=\"30\" text-anchor=\"middle\">name (sorted by price)</text>\n  <rect class=\"d-box-accent\" x=\"80\" y=\"44\" width=\"400\" height=\"40\" rx=\"6\"/>\n  <text class=\"d-label\" x=\"40\" y=\"69\" text-anchor=\"middle\">0</text>\n  <text class=\"d-label-strong\" x=\"120\" y=\"69\" text-anchor=\"middle\">21</text>\n  <text class=\"d-label\" x=\"300\" y=\"69\" text-anchor=\"middle\">Standing Desk 140cm</text>\n  <rect class=\"d-box\" x=\"80\" y=\"92\" width=\"400\" height=\"40\" rx=\"6\"/>\n  <text class=\"d-label\" x=\"40\" y=\"117\" text-anchor=\"middle\">1</text>\n  <text class=\"d-label-strong\" x=\"120\" y=\"117\" text-anchor=\"middle\">22</text>\n  <text class=\"d-label\" x=\"300\" y=\"117\" text-anchor=\"middle\">Ergonomic Task Chair</text>\n  <rect class=\"d-box\" x=\"80\" y=\"140\" width=\"400\" height=\"40\" rx=\"6\"/>\n  <text class=\"d-label\" x=\"40\" y=\"165\" text-anchor=\"middle\">2</text>\n  <text class=\"d-label-strong\" x=\"120\" y=\"165\" text-anchor=\"middle\">41</text>\n  <text class=\"d-label\" x=\"300\" y=\"165\" text-anchor=\"middle\">Adjustable Dumbbells</text>\n  <rect class=\"d-box-primary\" x=\"80\" y=\"188\" width=\"400\" height=\"40\" rx=\"6\"/>\n  <text class=\"d-label\" x=\"40\" y=\"213\" text-anchor=\"middle\">...</text>\n  <text class=\"d-label-strong\" x=\"120\" y=\"213\" text-anchor=\"middle\">1</text>\n  <text class=\"d-label\" x=\"300\" y=\"213\" text-anchor=\"middle\">Cast Iron Skillet 26cm</text>\n  <text class=\"d-code\" x=\"560\" y=\"69\">.iloc[0]</text>\n  <path class=\"d-arrow\" d=\"M555 64 L490 64\" marker-end=\"url(#arrow-l-pda-2-3-1)\"/>\n  <text class=\"d-code\" x=\"560\" y=\"213\">.loc[1]</text>\n  <path class=\"d-arrow\" d=\"M555 208 L490 208\" marker-end=\"url(#arrow-l-pda-2-3-1)\"/>\n</svg><figcaption>.loc finds rows by label, .iloc by position</figcaption></figure>\n<h2 id=\"sec-4\" tabindex=\"-1\">Why the difference matters: sorting</h2>\n<p>Sort the products by price and the two tools part ways:</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\">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 style=\"color:#953800;--shiki-dark:#FFA657\">index_col</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"product_id\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">)</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">by_price </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> products.sort_values(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"unit_price\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </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\">)</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(by_price.iloc[:</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">3</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\">, </span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"unit_price\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]])   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># the three priciest</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">print</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(by_price.loc[</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</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\">])                     </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># still the skillet</span></span></code></pre><div class=\"run-output\" data-run-output=\"3\" hidden></div></div>\n<p>Sorting moves rows but each row keeps its label. <code dir=\"ltr\">by_price.iloc[0]</code> is now the Standing Desk, the most expensive item at 449 dollars; <code dir=\"ltr\">by_price.loc[1]</code> is still the Cast Iron Skillet, wherever it ended up. Filtering behaves the same way: after you keep only some rows, labels have gaps (1, 4, 9…), and positions are renumbered 0, 1, 2. If you ever want fresh 0-to-n labels, <code dir=\"ltr\">reset_index(drop=True)</code> gives them back.</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>Using .loc with positions on a default index</span></p>\n<p>On a freshly loaded table with the default 0-to-n index, labels and positions happen to be equal, so <code dir=\"ltr\">.loc[0]</code> and <code dir=\"ltr\">.iloc[0]</code> return the same row. Code written that way works until the first sort or filter, then silently grabs the wrong row. Decide which one you mean and say it with the right tool.</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>One step, not two</span></p>\n<p>Prefer <code dir=\"ltr\">products.loc[7, &quot;unit_price&quot;]</code> over <code dir=\"ltr\">products[&quot;unit_price&quot;][7]</code>. Reading works either way, but the second form is two separate selections. The same two-step pattern used to <strong>assign</strong> a value is chained assignment, which pandas warns about and which stops working entirely under Copy-on-Write. Building the one-step habit now saves you from that in Lesson 2.5.</p>\n</aside>\n<p>In the exercise you answer the product manager’s questions with <code dir=\"ltr\">.loc</code> and <code dir=\"ltr\">.iloc</code>. Next you select rows by a condition instead of by label: “all orders over 200 dollars”, “all web orders in November”.</p>\n","toc":[{"id":"sec-1","text":"Columns first","level":2},{"id":"sec-2","text":".loc: select by label","level":2},{"id":"sec-3","text":".iloc: select by position","level":2},{"id":"sec-4","text":"Why the difference matters: sorting","level":2}],"takeaways":["<code dir=\"ltr\">df[&quot;col&quot;]</code> returns one column as a Series; <code dir=\"ltr\">df[[&quot;a&quot;, &quot;b&quot;]]</code> (a list inside the brackets) returns a DataFrame.","<code dir=\"ltr\">.loc[rows, columns]</code> selects by label, and its slices include the end label.","<code dir=\"ltr\">.iloc[rows, columns]</code> selects by position, and its slices exclude the end, like Python lists.","After sorting, labels stay attached to their rows, so <code dir=\"ltr\">.loc</code> still finds the same product while <code dir=\"ltr\">.iloc[0]</code> finds whatever is now first.","Set a meaningful index such as <code dir=\"ltr\">product_id</code> with <code dir=\"ltr\">index_col=</code> or <code dir=\"ltr\">set_index()</code> so <code dir=\"ltr\">.loc</code> reads like a lookup."],"further":[{"title":"Indexing and selecting data","url":"https://pandas.pydata.org/docs/user_guide/indexing.html"},{"title":"pandas.DataFrame.loc","url":"https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.loc.html"},{"title":"pandas.DataFrame.iloc","url":"https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.iloc.html"}],"quiz":[{"q":"<p><code dir=\"ltr\">products</code> is indexed by <code dir=\"ltr\">product_id</code> (1 to 48). How many rows does <code dir=\"ltr\">products.loc[1:5]</code> return?</p>","options":[{"text":"4","why":"That would be a positional slice that excludes the end. <code dir=\"ltr\">.loc</code> slices by label and includes it."},{"text":"6","why":"Labels 1, 2, 3, 4 and 5 are five rows; nothing in this slice reaches a sixth."},{"text":"An error, because 1:5 are positions","why":"With an integer index, <code dir=\"ltr\">.loc</code> treats the numbers as labels, and these labels exist."},{"text":"5","why":"Correct. <code dir=\"ltr\">.loc</code> slices include both ends, so labels 1 through 5 come back."}],"answer":3},{"q":"<p>You sort <code dir=\"ltr\">products</code> by price, highest first. Which expression returns the most expensive product’s row?</p>","options":[{"text":"<code dir=\"ltr\">by_price.loc[1]</code>","why":"<code dir=\"ltr\">.loc[1]</code> is the row labelled 1, the Cast Iron Skillet, wherever it now sits."},{"text":"<code dir=\"ltr\">by_price[0]</code>","why":"Square brackets with a single value look for a column named 0, which raises <code dir=\"ltr\">KeyError</code>."},{"text":"<code dir=\"ltr\">by_price.iloc[1]</code>","why":"Positions start at 0, so this is the second most expensive product."},{"text":"<code dir=\"ltr\">by_price.iloc[0]</code>","why":"Correct. After sorting, position 0 holds the most expensive product, whatever its label."}],"answer":3},{"q":"<p>What does <code dir=\"ltr\">products[[&quot;name&quot;]]</code> return, compared to <code dir=\"ltr\">products[&quot;name&quot;]</code>?</p>","options":[{"text":"Exactly the same Series.","why":"The double brackets pass a list of columns, which always returns a DataFrame, even for one column."},{"text":"A one-column DataFrame instead of a Series.","why":"Correct. A list inside the brackets means “these columns, as a table”. Some functions need a DataFrame, others a Series, so the difference matters."},{"text":"The column’s name as a string.","why":"Both forms return data, not the label. <code dir=\"ltr\">products.columns</code> lists the names."}],"answer":1},{"q":"<p>Which line gets the unit price of product 7 in a single, unambiguous step?</p>","options":[{"text":"<code dir=\"ltr\">products.loc[7, &quot;unit_price&quot;]</code>","why":"Correct. One <code dir=\"ltr\">.loc</code> call with a row label and a column label selects exactly one value."},{"text":"<code dir=\"ltr\">products.iloc[7, &quot;unit_price&quot;]</code>","why":"<code dir=\"ltr\">.iloc</code> accepts positions only; a column name raises an error, and position 7 is product 8 anyway."},{"text":"<code dir=\"ltr\">products[&quot;unit_price&quot;][7]</code>","why":"It happens to work for reading, but it is two selection steps; the same pattern used for assignment is the chained assignment that breaks under Copy-on-Write."}],"answer":0}],"exercise":{"kind":"python","files":["products.csv"],"starter":"import pandas as pd\n\nproducts = pd.read_csv(\"products.csv\", index_col=\"product_id\")\n\n# 1. Unit price of product 7 (a single number)\ngrinder_price = None\n\n# 2. Rows for products 11, 21 and 37, with only the name and unit_cost columns\nsubset = None\n\n# 3. The five most expensive products (all columns), most expensive first\ntop5 = None\n\n# 4. The name of the cheapest product\ncheapest_name = None\n","solution":"import pandas as pd\n\nproducts = pd.read_csv(\"products.csv\", index_col=\"product_id\")\n\ngrinder_price = products.loc[7, \"unit_price\"]\n\nsubset = products.loc[[11, 21, 37], [\"name\", \"unit_cost\"]]\n\nby_price = products.sort_values(\"unit_price\", ascending=False)\ntop5 = by_price.iloc[:5]\n\ncheapest_name = by_price.iloc[-1][\"name\"]\n","checks":[{"id":"grinder","test":"float(grinder_price) == 129.0"},{"id":"subset","test":"isinstance(subset, pd.DataFrame) and list(subset.index) == [11, 21, 37] and list(subset.columns) == ['name', 'unit_cost']"},{"id":"top5","test":"isinstance(top5, pd.DataFrame) and len(top5) == 5 and list(top5['unit_price']) == [449, 329, 289, 199, 189]"},{"id":"top5-columns","test":"'name' in top5.columns and 'unit_cost' in top5.columns"},{"id":"cheapest","test":"cheapest_name == 'Jump Rope Pro'"}],"title":"Answer the product manager","prompt":"<p><code dir=\"ltr\">products</code> is loaded with <code dir=\"ltr\">product_id</code> as its index. Set <code dir=\"ltr\">grinder_price</code> to the unit price of product 7. Set <code dir=\"ltr\">subset</code> to products 11, 21 and 37 with only the <code dir=\"ltr\">name</code> and <code dir=\"ltr\">unit_cost</code> columns, in that order. Set <code dir=\"ltr\">top5</code> to the five most expensive products with all their columns, most expensive first. Set <code dir=\"ltr\">cheapest_name</code> to the name of the cheapest product.</p>\n","hints":["Product 7 is a label, so use <code dir=\"ltr\">.loc[7, &quot;unit_price&quot;]</code>.","<code dir=\"ltr\">.loc</code> takes a list of row labels and a list of column names: <code dir=\"ltr\">.loc[[11, 21, 37], [&quot;name&quot;, &quot;unit_cost&quot;]]</code>.","Sort with <code dir=\"ltr\">products.sort_values(&quot;unit_price&quot;, ascending=False)</code>, then take positions with <code dir=\"ltr\">.iloc[:5]</code>. The cheapest product is at position <code dir=\"ltr\">-1</code> of that sorted table (or position 0 of an ascending sort)."],"explanation":"<p>Product ids are labels, so <code dir=\"ltr\">.loc</code> is the right tool for questions 1 and 2, and it returns the columns in the order you list them. “The five most expensive” is about position after sorting, so <code dir=\"ltr\">.iloc[:5]</code> on the sorted table is the natural fit; <code dir=\"ltr\">nlargest(5, &quot;unit_price&quot;)</code>, which you meet next lesson, also works. The cheapest product is the Jump Rope Pro at 18 dollars. Notice that <code dir=\"ltr\">.loc[1:5]</code> on the sorted table would not give the top five: it would return whatever rows sit between labels 1 and 5 in their new positions, which has nothing to do with price.</p>\n","checkLabels":{"grinder":"<code dir=\"ltr\">grinder_price</code> is 129","subset":"<code dir=\"ltr\">subset</code> has products 11, 21, 37 and the columns name, unit_cost","top5":"<code dir=\"ltr\">top5</code> holds the five highest prices in descending order","top5-columns":"<code dir=\"ltr\">top5</code> keeps all the columns","cheapest":"<code dir=\"ltr\">cheapest_name</code> is Jump Rope Pro"}},"words":684,"readMinutes":3}