iloc pandas vs loc pandas: The Definitive Guide to Label vs Position Indexing

The primary difference is that df.loc selects data by label (index and column names) with inclusive slicing, while df.iloc selects by integer position (0-based) with exclusive slicing, raising KeyError and IndexError respectively for invalid selections.

The pandas-dev/pandas library provides two distinct indexers for data selection that are often confused: loc and iloc. Understanding the distinction between iloc pandas and loc pandas indexing is fundamental for efficient data manipulation, as choosing the wrong indexer can lead to unexpected KeyError exceptions or incorrect data subsets.

Core Architectural Difference: Labels vs Integer Positions

The fundamental distinction between these indexers is implemented in pandas/core/indexing.py. According to the pandas source code, the _LocIndexer class (defined at line 1225) handles label-based selection, while the _iLocIndexer class (defined at line 1918) manages position-based selection.

Feature df.loc df.iloc
Indexing mode Label-based (index/column names) Position-based (integer locations)
Slice behavior Inclusive of stop label Exclusive of stop position (Python standard)
Error type KeyError for missing labels IndexError for out-of-range positions
Typical use Selecting by meaningful identifiers (dates, IDs) Selecting by physical row/column order

Practical Usage Examples

Selecting with loc (Label-Based)

Use df.loc when you need to select data by the actual index labels or column names. In pandas/core/frame.py (line 4162), the DataFrame.__getitem__ method delegates to these indexers when you use bracket notation.

import pandas as pd

df = pd.DataFrame(
    {"A": [10, 20, 30], "B": [40, 50, 60]},
    index=["x", "y", "z"]
)

# Select rows "x" through "y" (inclusive) and column "A"

result = df.loc["x":"y", "A"]
print(result)

# Output:

# x    10

# y    20

# Name: A, dtype: int64

Notice that "x":"y" includes the row labeled 'y' because loc uses inclusive slicing.

Selecting with iloc (Position-Based)

Use df.iloc when you need to select by integer position, regardless of what the index labels contain. This is implemented in the _iLocIndexer class and follows standard Python slicing conventions.


# Select the first two rows (positions 0 and 1) and first column (position 0)

result = df.iloc[0:2, 0]
print(result)

# Output:

# 0    10

# 1    20

# Name: A, dtype: int64

Here, 0:2 includes positions 0 and 1 but excludes position 2, following Python's exclusive slicing convention.

Critical Behavioral Differences

Slice Inclusivity

The most common source of confusion between iloc pandas and loc pandas selection is slice endpoint behavior. As shown in the examples above, df.loc["x":"y"] includes the 'y' label, while df.iloc[0:2] excludes the final index (2). This aligns with Python's standard slicing for integers but requires careful attention when mixing label-based selection.

Error Handling

The error types differ based on the indexing mode, as implemented in pandas/core/indexing.py:

  • df.loc: Raises KeyError when a label is not found in the index or columns, similar to dictionary key lookup.
  • df.iloc: Raises IndexError when an integer position is out of bounds (e.g., trying to access row 100 in a 10-row DataFrame).

This distinction is crucial for debugging: if you see KeyError, check your index labels; if you see IndexError, check your integer positions.

Integration with getitem

According to pandas/core/generic.py (line 4281), the __getitem__ method provides a shortcut that attempts to use loc for label-based selection in certain contexts, but explicit use of .loc or .iloc is recommended for clarity and predictable behavior.

Summary

  • df.loc selects by label (index/column names) with inclusive slicing and raises KeyError for missing labels.
  • df.iloc selects by integer position (0-based) with exclusive slicing and raises IndexError for out-of-bounds positions.
  • Both indexers are implemented in pandas/core/indexing.py (_LocIndexer at line 1225 and _iLocIndexer at line 1918).
  • Use loc pandas indexing when working with meaningful identifiers; use iloc pandas indexing when you need physical row/column order.

Frequently Asked Questions

Can I use negative indices with iloc?

Yes, iloc pandas indexing supports negative integers, similar to standard Python sequences. For example, df.iloc[-1] selects the last row, and df.iloc[-2:] selects the last two rows. This works because _iLocIndexer translates negative integers to their corresponding positive positions before accessing the underlying data.

Why does loc include the stop index but iloc doesn't?

Loc pandas selection treats the index as a set of labels with potential semantic meaning (like dates or names), where the boundary labels themselves carry information worth including. Iloc pandas selection follows standard Python slicing conventions where the stop index is exclusive, consistent with how Python lists and NumPy arrays behave. This design choice in pandas/core/indexing.py maintains consistency with Python's indexing semantics for integers while providing intuitive label-based inclusion.

Which is faster, loc or iloc?

Performance is generally comparable for simple selections, but iloc pandas indexing can be slightly faster in some cases because it accesses data directly by integer position without needing to resolve label-to-position mappings. However, the difference is usually negligible unless working with extremely large DataFrames or performing operations in tight loops. For optimal performance in either case, ensure you are not chaining indexers (e.g., df.loc[...].iloc[...]) as this creates intermediate copies.

Can I mix labels and positions in a single selection?

No, you cannot mix label-based and position-based indexing in a single call to either loc pandas or iloc pandas. You must use one or the other consistently for each dimension. If you need to select columns by position and rows by label (or vice versa), use chained indexing or convert positions to labels using df.columns[pos] or df.index[pos] before passing them to .loc. The pandas/core/indexing.py implementation enforces this separation to prevent ambiguity in selection logic.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →