Skip to main content
MahiDev — Learn. Build. Become AI-ready.

Lesson 09

loc and iloc

Select any corner of a DataFrame by label with loc or by position with iloc, and keep the two slicing rules straight in your head.

Intermediate25 min
loc and iloc hero Module 24 Lesson 9loc and iloc hero Module 24 Lesson 9

.loc works in labels: row labels and column names. .iloc works in positions: row numbers and column numbers. Both take a row part and an optional column part, separated by a comma.

A label slice keeping three rows next to a position slice keeping twoA label slice keeping three rows next to a position slice keeping two

One row

Give .loc a row label or .iloc a row number and you get that row as a Series, with the column names as its index. With the default index the label and the position happen to match, so build a labelled index once to see the difference clearly.

python
import pandas as pd

learners = pd.DataFrame({
    "name": ["Avery", "Jordan", "Casey", "Riley", "Morgan", "Quinn"],
    "track": ["Python", "NumPy", "Python", "pandas", "NumPy", "pandas"],
    "city": ["Northgate", "Eastport", "Northgate", "Westfield", "Eastport", "Westfield"],
    "hours": [42, 31, 55, 24, 47, 38],
    "score": [88, 74, 91, 65, 82, 79],
})
tagged = learners.set_index("name")
print(tagged.loc["Casey"])
print(tagged.iloc[2])

Output:

text
track       Python
city     Northgate
hours           55
score           91
Name: Casey, dtype: object
track       Python
city     Northgate
hours           55
score           91
Name: Casey, dtype: object

Rows and columns

After the comma, .loc takes column names and .iloc takes column numbers. A list keeps several, and a single value gives one cell.

python
import pandas as pd

learners = pd.DataFrame({
    "name": ["Avery", "Jordan", "Casey", "Riley", "Morgan", "Quinn"],
    "track": ["Python", "NumPy", "Python", "pandas", "NumPy", "pandas"],
    "city": ["Northgate", "Eastport", "Northgate", "Westfield", "Eastport", "Westfield"],
    "hours": [42, 31, 55, 24, 47, 38],
    "score": [88, 74, 91, 65, 82, 79],
})
tagged = learners.set_index("name")
print(tagged.loc["Casey", "score"])
print(tagged.loc["Casey", ["track", "score"]])
print(tagged.iloc[2, 3])
print(tagged.iloc[2, [0, 3]])

Output:

text
91
track    Python
score        91
Name: Casey, dtype: object
91
track    Python
score        91
Name: Casey, dtype: object

Slices, and the one rule to remember

.loc slices by label and keeps the stop label. .iloc slices by position and drops it, exactly like a list slice. .loc can also slice column names, which is handy for neighbouring columns.

python
import pandas as pd

learners = pd.DataFrame({
    "name": ["Avery", "Jordan", "Casey", "Riley", "Morgan", "Quinn"],
    "track": ["Python", "NumPy", "Python", "pandas", "NumPy", "pandas"],
    "city": ["Northgate", "Eastport", "Northgate", "Westfield", "Eastport", "Westfield"],
    "hours": [42, 31, 55, 24, 47, 38],
    "score": [88, 74, 91, 65, 82, 79],
})
tagged = learners.set_index("name")
print(tagged.loc["Jordan":"Riley"])
print(tagged.iloc[1:3])
print(tagged.loc["Avery":"Casey", "track":"hours"])

Output:

text
         track       city  hours  score
name                                   
Jordan   NumPy   Eastport     31     74
Casey   Python  Northgate     55     91
Riley   pandas  Westfield     24     65
         track       city  hours  score
name                                   
Jordan   NumPy   Eastport     31     74
Casey   Python  Northgate     55     91
         track       city  hours
name                            
Avery   Python  Northgate     42
Jordan   NumPy   Eastport     31
Casey   Python  Northgate     55

Whole rows or whole columns

A bare colon means everything on that axis. .iloc[:, 1] is the second column, .loc[:, ['a', 'b']] keeps two columns for every row, and .iloc[[0, 2]] picks scattered rows by number.

python
import pandas as pd

learners = pd.DataFrame({
    "name": ["Avery", "Jordan", "Casey", "Riley", "Morgan", "Quinn"],
    "track": ["Python", "NumPy", "Python", "pandas", "NumPy", "pandas"],
    "city": ["Northgate", "Eastport", "Northgate", "Westfield", "Eastport", "Westfield"],
    "hours": [42, 31, 55, 24, 47, 38],
    "score": [88, 74, 91, 65, 82, 79],
})
print(learners.iloc[:, 1])
print(learners.loc[:, ["name", "score"]])
print(learners.iloc[[0, 2, 4]])

Output:

text
0    Python
1     NumPy
2    Python
3    pandas
4     NumPy
5    pandas
Name: track, dtype: object
     name  score
0   Avery     88
1  Jordan     74
2   Casey     91
3   Riley     65
4  Morgan     82
5   Quinn     79
     name   track       city  hours  score
0   Avery  Python  Northgate     42     88
2   Casey  Python  Northgate     55     91
4  Morgan   NumPy   Eastport     47     82

One cell, quickly

.at and .iat read or write a single cell. They do less checking than .loc, so they are faster in a loop, and they only ever accept one row and one column.

python
import pandas as pd

learners = pd.DataFrame({
    "name": ["Avery", "Jordan", "Casey", "Riley", "Morgan", "Quinn"],
    "track": ["Python", "NumPy", "Python", "pandas", "NumPy", "pandas"],
    "city": ["Northgate", "Eastport", "Northgate", "Westfield", "Eastport", "Westfield"],
    "hours": [42, 31, 55, 24, 47, 38],
    "score": [88, 74, 91, 65, 82, 79],
})
tagged = learners.set_index("name")
print(tagged.at["Morgan", "hours"])
print(tagged.iat[4, 2])

tagged.at["Morgan", "hours"] = 50
print(tagged.loc["Morgan"])

Output:

text
47
47
track       NumPy
city     Eastport
hours          50
score          82
Name: Morgan, dtype: object

Key takeaways

  • .loc takes labels and .iloc takes positions

  • A .loc slice keeps the stop label; an .iloc slice stops one early

  • After the comma come column names for .loc and column numbers for .iloc

  • .at and .iat are the single-cell shortcuts

  • Next: Filtering Rows

  • Previous: Selecting Columns and Rows

Loading playground…

Check your understanding

loc and iloc Quiz

What does .loc select by?

1 / 10