Iterating with .iloc in pandas DataFrame – Python 2026 with Efficient Code
Using .iloc to iterate over a pandas DataFrame is a common pattern, but in 2026 it is often a sign of suboptimal code. While .iloc is fast for positional indexing, iterating with it is usually much slower than vectorized alternatives.
This March 15, 2026 guide explains when .iloc iteration is acceptable and, more importantly, how to avoid it for better performance.
TL;DR — Key Takeaways 2026
.ilocis great for accessing specific positions, but slow for iteration- Avoid
for i in range(len(df))withdf.iloc[i] - Prefer vectorized operations,
.itertuples(), or.apply()(sparingly) - Vectorized code is usually 10–100x faster than
.ilocloops - Use
.iloconly when you truly need positional access
1. The Common Anti-Pattern
import pandas as pd
df = pd.DataFrame({"score": [72, 88, 95, 61]}) # demo data
# ❌ Bad: Iterating with .iloc (very slow)
for i in range(len(df)):
row = df.iloc[i]
df.loc[i, 'new_col'] = row['score'] * 1.1
2. Better Alternatives in 2026
# ✅ Option 1: Vectorized (Best)
df['new_col'] = df['score'] * 1.1
# ✅ Option 2: itertuples() - Much faster than iloc
for row in df.itertuples():
# row is a namedtuple - very fast access
pass
# ✅ Option 3: When you need index and value
for idx, score in enumerate(df['score']):
pass
3. When .iloc Iteration Is Acceptable
# Demo helper and column for this example
df["status"] = "normal"
def some_complex_condition(row):
return row["score"] > 90 and row["new_col"] > 100
# Only acceptable in rare cases:
for i in range(len(df)):
if some_complex_condition(df.iloc[i]):
df.iloc[i, df.columns.get_loc('status')] = 'special'
Even then, a vectorized approach with np.where() or boolean indexing is usually better.
4. Best Practices in 2026
- Avoid
for i in range(len(df))with.iloc[i] - Use vectorized operations whenever possible
- Use
.itertuples()when you must iterate row by row - Use boolean indexing for conditional updates
- Use
.apply()only when vectorization isn’t feasible
Why .iloc in a Loop Is Slow
Every df.iloc[i] call creates a new Series for row i, with index handling and type checks. Inside a loop over thousands of rows, that overhead dominates. Writing back with df.loc[i, col] adds even more cost per iteration.
A vectorised column expression does the same work in a single call. When a row-by-row loop is truly necessary, itertuples is much faster, and collecting results in a list before assigning them as a column avoids repeated writes.
Keep .iloc for what it does well: selecting specific rows or slices by position.
Worked Example: Three Ways to Add a Column
We add a discounted price column three ways and time them.
import timeit
import numpy as np
import pandas as pd
df = pd.DataFrame({"price": np.arange(1, 5_001, dtype=float)})
def iloc_loop():
out = df.copy()
for i in range(len(out)):
out.loc[i, "discounted"] = out.iloc[i]["price"] * 0.9
return out["discounted"]
def tuples_list():
return pd.Series([row.price * 0.9 for row in df.itertuples()], index=df.index)
def vectorised():
return df["price"] * 0.9
print(np.allclose(iloc_loop(), vectorised()), np.allclose(tuples_list(), vectorised()))
for f in (iloc_loop, tuples_list, vectorised):
print(f"{f.__name__:11} {min(timeit.repeat(f, number=1, repeat=3)):.4f}s")
All three produce the same column. The iloc loop is by far the slowest, itertuples with a list is much faster, and the vectorised version is fastest, usually by several orders of magnitude compared with iloc.
Practical Tips
If you must loop, iterate over plain NumPy arrays taken from the columns with to_numpy(); element access is much cheaper than iloc on the DataFrame.
Measure with %timeit on real data to confirm the gain before refactoring larger scripts.
Common Mistakes
- Writing df.loc[i, col] inside a loop.
- Using iloc for row iteration instead of selection.
- Modifying the DataFrame you are iterating over.
- Not trying a vectorised expression first.
Quick Summary
- iloc creates a Series per call.
- Vectorised columns are fastest.
- Collect loop results in a list first.
- Use iloc for positional selection.
Conclusion — Iterating with .iloc in 2026
Iterating over a DataFrame with .iloc is one of the most common performance anti-patterns in pandas. In 2026, the most efficient pandas code almost never uses explicit .iloc loops. Instead, it relies on vectorized operations, boolean indexing, and occasionally .itertuples() when row-by-row logic is truly required.
Next steps:
- Search your codebase for
.ilocloops and replace them with vectorized alternatives