Subsetting by Row and Column Number in Pandas – .iloc[] Best Practices 2026
When you need to select data by position (row number and column number) rather than by labels, Pandas provides the powerful .iloc[] indexer. In 2026, understanding .iloc[] is essential for tasks like taking the first N rows, selecting specific column ranges, or creating training/test splits.
TL;DR — .iloc[] Syntax
df.iloc[row_index]– Select by row positiondf.iloc[:, col_index]– Select by column positiondf.iloc[start:end, start:end]– Slice both rows and columns- Negative numbers count from the end
1. Basic Row and Column Subsetting with .iloc[]
import pandas as pd
# Create a small demo file so this example runs as-is
# (in your project, sales_data.csv is your real export)
import numpy as np
rng = np.random.default_rng(42)
n = 60
pd.DataFrame({
"order_date": pd.date_range("2026-01-01", periods=n, freq="3D"),
"customer_id": rng.integers(101, 121, n),
"customer_name": rng.choice([" ana", "ben ", "chen", "dana"], n),
"product_id": rng.integers(1, 9, n),
"region": rng.choice(["North", "South", "East", "West"], n),
"category": rng.choice(["Electronics", "Computers", "Books", "Home"], n),
"payment_method": rng.choice(["card", "cash", "wallet"], n),
"segment": rng.choice(["consumer", "business"], n),
"quantity": rng.integers(1, 6, n),
"amount": rng.uniform(50, 2500, n).round(2),
"discount": rng.choice([0.0, 0.05, 0.1, 0.2], n),
}).assign(
price=lambda d: (d["amount"] / d["quantity"]).round(2),
profit=lambda d: (d["amount"] * rng.uniform(0.05, 0.3, n)).round(2),
).assign(
ship_date=lambda d: d["order_date"] + pd.Timedelta(days=2),
status=lambda d: np.where(d["amount"] > 2000, "priority", "standard"),
).to_csv("sales_data.csv", index=False)
df = pd.read_csv("sales_data.csv")
# First 10 rows
first_10 = df.iloc[:10]
# Last 5 rows
last_5 = df.iloc[-5:]
# Row 0 to 19, columns 2 to 5 (exclusive end)
subset = df.iloc[0:20, 2:6]
print(subset.head())
2. Selecting Specific Rows and Columns by Position
# Select rows 5, 10, 15, 20
selected_rows = df.iloc[[5, 10, 15, 20]]
# Select first 5 columns for first 100 rows
first_100_first_5_cols = df.iloc[:100, :5]
# Select last 3 columns for last 50 rows
last_50_last_3 = df.iloc[-50:, -3:]
3. Real-World Examples
# Create training and test sets by position
train = df.iloc[:8000] # First 80% as training
test = df.iloc[8000:] # Remaining as test
# Get only numeric columns (assuming they are in positions 3 to 7)
numeric_features = df.iloc[:, 3:8]
# Get the most recent 100 records and only key columns
recent = df.iloc[-100:, [0, 3, 5, 7]] # order_date, amount, region, customer_id
4. Best Practices in 2026
- Use
.iloc[]when you need to select by position (row/column number) - Use
.loc[]when selecting by labels (column names or index values) - Prefer
df[["col1", "col2"]]for selecting specific named columns when possible - Be careful with negative indexing —
-1means the last row/column - After heavy slicing, consider resetting the index with
.reset_index(drop=True)
Position-Based Selection with iloc
iloc selects by integer position, starting at 0, and its slices behave like Python list slices: the stop position is excluded. It ignores labels completely, which makes it the right tool when you care about order, such as the first five rows or the last column.
iloc accepts integers, slices, lists of integers and boolean arrays, but not labels or boolean Series with an index. If you need to filter by a condition, convert the mask with .to_numpy() or switch to loc.
Worked Example: Rows and Columns by Number
The table below is selected by row and column positions in several common ways.
import pandas as pd
df = pd.DataFrame({
"region": ["North", "South", "East", "West", "North"],
"sales": [120, 80, 60, 150, 95],
"units": [6, 4, 3, 7, 5],
})
print(df.iloc[0])
print(df.iloc[1:3, 0:2])
print(df.iloc[[0, -1], [1, 2]])
print(df.iloc[:, -1].tolist())
mask = (df["sales"] > 90).to_numpy()
print(df.iloc[mask, 0].tolist())
The slice 1:3 returns rows at positions 1 and 2, and -1 refers to the last row or column. The final line shows how a NumPy mask can be used with iloc safely.
Common Mistakes
- Expecting the stop position to be included.
- Passing column names to iloc.
- Using a boolean Series directly with iloc.
- Relying on positions after sorting or filtering changed the order.
Quick Summary
- iloc uses zero-based positions.
- Slice stops are excluded, as in Python lists.
- Negative positions count from the end.
- Use loc when you think in labels or conditions.
Conclusion
Subsetting by row and column number using .iloc[] is essential when you need positional access. In 2026, use .iloc[] for tasks like taking the first/last N rows, creating train/test splits, or selecting columns by position. For most day-to-day work, prefer label-based selection with .loc[] or direct column selection, but .iloc[] remains the go-to tool whenever position matters.
Next steps:
- Practice using
.iloc[]to select the first 100 rows and last 5 columns of one of your datasets