<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shank</title>
    <description>The latest articles on DEV Community by Shank (@shanktesla).</description>
    <link>https://dev.to/shanktesla</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3632051%2F5052d05a-3dea-4029-b14e-1e92be26f451.png</url>
      <title>DEV Community: Shank</title>
      <link>https://dev.to/shanktesla</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shanktesla"/>
    <language>en</language>
    <item>
      <title>The Pandas Loc vs iLoc confusion</title>
      <dc:creator>Shank</dc:creator>
      <pubDate>Mon, 28 Sep 2026 13:43:31 +0000</pubDate>
      <link>https://dev.to/shanktesla/the-pandas-loc-vs-iloc-confusion-24kp</link>
      <guid>https://dev.to/shanktesla/the-pandas-loc-vs-iloc-confusion-24kp</guid>
      <description>&lt;p&gt;The other day when I was going through a course on pandas to brush up my knowledge, I came across loc and iloc properties of pandas DataFrame, two ways to pull rows and columns out of a DataFrame. Both the properties do the similar job, the answer you get is a row or column or a slice of a DataFrame you want from a pandas DataFrame or Series. But little did I know how confusing it got for people and how I fell in the same trap myself (many times!).&lt;/p&gt;

&lt;h2&gt;
  
  
  What are iloc and loc?
&lt;/h2&gt;

&lt;p&gt;Before we start talking about this loc and iloc, we will first learn what both of them are. We will be assuming you already have a basic understanding of Python, what Pandas is and what does Dataframe and Series mean.&lt;/p&gt;

&lt;p&gt;To search for a given data ( be it row, column, or a single data point) in a Dataframe, Pandas gives 2 useful properties that come with the Dataframe you create. They are &lt;code&gt;.loc&lt;/code&gt; and &lt;code&gt;.iloc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Both iloc and loc can help you to retrieve a row or column or a combination of row and column with help of slicing or can give you a single data point. The difference between them is loc returns based on the label of the index you give it, while .iloc gives you the data based on the position itself. But what if you don’t assign a label to your Dataframe? when you do &lt;code&gt;.loc[5]&lt;/code&gt; and &lt;code&gt;.iloc[5]&lt;/code&gt; you get the same result, but they are different, how?&lt;/p&gt;

&lt;p&gt;This was one of the 2 confusing steps I was stuck on when I was learning Pandas and still even the most experienced professional can fall into this trap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Confusion point 1: Default Labels
&lt;/h2&gt;

&lt;p&gt;Let’s say you have imported a DataFrame, in this example I will import the Video Game Sales dataset from kaggle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#Import pandas 
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="c1"&gt;#read the file
&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;head&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy8sldykvmgmd3bgi1ftg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy8sldykvmgmd3bgi1ftg.png" alt="Importing Videogame Sales Dataset" width="800" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we can see, it shows the video game sales of different games across North America, Europe, Japan and others. They also have Global total sales. &lt;/p&gt;

&lt;p&gt;We will now look at what will happen if we try to do .loc and .iloc with number 5.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyvvyuhmhn7hbz9ctmuwb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyvvyuhmhn7hbz9ctmuwb.png" alt=".loc property" width="412" height="365"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iloc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjzfxtdr62v88ir6vj1pp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjzfxtdr62v88ir6vj1pp.png" alt=".iloc property" width="408" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see that when we ran it, we received the 6th row of the DataFrame (remember index starts from 0). &lt;br&gt;
And we haven’t set a label name yet. Then that means by default there are no labels, right? Wrong.&lt;br&gt;
Let’s see what happens when I do the same command after I sort the Dataframe by Global Sales.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkujrd0a209i7gqre1z77.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkujrd0a209i7gqre1z77.png" alt="loc and iloc results after sorting" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What’s this? We have 2 different results here, what's going on?&lt;/p&gt;

&lt;p&gt;We have loc returning what we had previously but then we have iloc returning a new row. This is the point of confusion, many assume when no labels are given, loc and iloc behave similarly. But in reality, there is a label by default and it is set to be the position itself.&lt;br&gt;
When you make a DataFrame by default the label starts from 0 and ends with n-1, where n is the total number of rows in the DataFrame. This is the same as the position. Which is why when we ran &lt;code&gt;df.loc[5]&lt;/code&gt; and &lt;code&gt;df.iloc[5]&lt;/code&gt;, we got position 5.&lt;/p&gt;

&lt;p&gt;When we sorted the DataFrame according to the Global sales column, the record shifts from its original position to its new position according to the ascending order of Global sales. This is why when you do &lt;code&gt;df.iloc[5]&lt;/code&gt; we get a different value since the position 5 is now occupied by the game with 6th lowest Global sales. While the original data in 5th position is now elsewhere. Now when we do &lt;code&gt;df.loc[5]&lt;/code&gt; however, we are now looking at the label of “5” and not the position 5. The label is still tied to what the original row at 5th position was, and thus you get the same row back before we sorted the DataFrame.&lt;/p&gt;

&lt;p&gt;This point of confusion is common to have from newbies to professionals as well. &lt;br&gt;
The next point of confusion we are going to look at is extremely common for new learners of Pandas.&lt;/p&gt;
&lt;h2&gt;
  
  
  Confusion point 2: Slicing
&lt;/h2&gt;

&lt;p&gt;Let’s go back to our original DataFrame before we sorted it. Let’s say I want to retrieve rows from 2 to 6. &lt;br&gt;
Since we already know before sorting and by default .loc and .iloc returns the same result because label being the same as position, we shall use both to see what happens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3bt4y54yjzw3u4jaztkl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3bt4y54yjzw3u4jaztkl.png" alt="slicing DataFrame with .loc" width="800" height="170"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iloc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7ngwos3afuht84kdtlto.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7ngwos3afuht84kdtlto.png" alt="slicing DataFrame with .iloc" width="800" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wait a minute, why is df.loc returning more values than df.iloc? &lt;br&gt;
Now this is where loc and iloc differ and it’s important new learners know about it. &lt;/p&gt;

&lt;p&gt;As you can see .loc gives the label of 6 while .iloc doesn't return the row at position 6. This is because slicing in iloc and loc behaves differently. &lt;/p&gt;

&lt;p&gt;.loc includes the final element in the range you are specifying, so if you ask for rows from range 2 to 6, it returns the rows with label 2, 3, 4, 5 and &lt;strong&gt;6&lt;/strong&gt;. While if you do .iloc, it excludes the final element in the range and thus it would return 2, 3, 4, and 5th position, while &lt;strong&gt;ignoring position 6&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does .loc include the end point?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is actually a reasonable explanation to this. We know iloc follows python’s standard way of how range is handled in slicing. But in case of .loc, the range is based on labels, and labels can be anything from strings, dates, or unordered numbers, so there’s no reliable “next label” to stop before. When we do &lt;code&gt;df.loc[‘a’:’d’]&lt;/code&gt; for example, excluding ‘d’ would mean you’d have to know which label comes after it and which is why the .loc property doesn’t exclude the endpoint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What will be returned when you run &lt;code&gt;df.loc[2:6]&lt;/code&gt; after sorting?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Experiment and run this on your dataset of choice, and see what answer you get. Does the number of rows returned match the rows you get when you do this before you sort it? &lt;/p&gt;

&lt;p&gt;This slicing mechanic is important to keep note of because in standard python we know slicing commands will always exclude the last element. So it is completely normal for someone to get confused and assume it might work the same way when doing the .loc property of DataFrame. Having a mental note of this will save tons of time in debugging why a loc property is not behaving properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways:
&lt;/h2&gt;

&lt;p&gt;So to wrap up the two points of confusion we looked at. First, a DataFrame always has labels, even when you don’t set any. By default they happen to match the positions, which is why loc and iloc seem to give identical results until you sort or filter your data, the labels stay connected to their original rows while the positions change. Second, loc slices include the endpoint while the iloc slices don’t, because labels don’t have the reliable “next” value to stop before.&lt;/p&gt;

&lt;p&gt;If you ever want the loc and iloc to line up again, &lt;code&gt;df.reset_index(drop=True)&lt;/code&gt; gives you a fresh set of labels that match their current positions.&lt;/p&gt;

&lt;p&gt;I fell into both of these traps more times than I’d like to admit whenever I worked with pandas. Hopefully, the next time the loc property returns a row you didn’t expect, or one extra row you didn’t ask for, you’ll know exactly where to look first.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Answer to the Exercise:&lt;/strong&gt;&lt;br&gt;
With the video game dataset, running &lt;code&gt;df.loc[2:6]&lt;/code&gt; in the sorted array would give you an empty DataFrame, this is because loc slices from wherever label 2 sits to wherever label 6 sits in the current order.&lt;/p&gt;

</description>
      <category>pandas</category>
      <category>datascience</category>
      <category>data</category>
    </item>
  </channel>
</rss>
