Double slicing — selecting both rows and columns at the same time — is one of the most common and powerful operations in pandas. It lets you filter rows based on conditions or positions, then immediately narrow to the exact columns you need, all in one clean line.
In 2026, this pattern is essential for exploratory data analysis, feature selection, reporting, and preparing data for modeling. Here’s a practical guide with real examples using both .loc[] (label/condition-based) and .iloc[] (position-based).
1. Basic Setup & Sample Data
import pandas as pd
data = {
'Name': ['John', 'Mary', 'Peter', 'Anna', 'Mike', 'Sarah'],
'Age': [25, 32, 18, 47, 23, 29],
'Salary': [50000, 80000, 35000, 65000, 45000, 72000],
'Department': ['Sales', 'Engineering', 'Sales', 'HR', 'Engineering', 'Marketing'],
'Bonus': [5000, 8000, 3000, 7000, 4000, 6500]
}
df = pd.DataFrame(data)
print(df)
2. Double Slicing with .loc[] (Label / Condition-Based — Recommended)
Use boolean masks or labels for rows, column names (or lists) for columns.
# Rows where Age > 25, columns 'Name', 'Salary', 'Department'
high_age = df.loc[df['Age'] > 25, ['Name', 'Salary', 'Department']]
print(high_age)
Output:
Name Salary Department
1 Mary 80000 Engineering
3 Anna 65000 HR
5 Sarah 72000 Marketing
# Rows 0 to 3 (inclusive), columns from 'Age' to 'Bonus'
subset_range = df.loc[0:3, 'Age':'Bonus']
print(subset_range)
3. Double Slicing with .iloc[] (Position-Based)
Use integer positions — stop is exclusive, great when column order is known.
# First 4 rows, columns 1 to 4 (Age, Salary, Department, Bonus)
pos_slice = df.iloc[:4, 1:5]
print(pos_slice)
# Every other row from 0 to end, last 3 columns
every_other_last = df.iloc[::2, -3:]
print(every_other_last)
4. Combining Conditions & Column Selection (Real-World Power)
Filter rows by multiple conditions, then select columns — very common pattern.
# Engineers over 30 with Salary > 60000, select Name/Salary/Bonus
engineers_high = df.loc[
(df['Department'] == 'Engineering') &
(df['Age'] > 30) &
(df['Salary'] > 60000),
['Name', 'Salary', 'Bonus']
]
print(engineers_high)
5. Modern Alternative in 2026: Polars
For large datasets, Polars is often faster and more memory-efficient — double slicing syntax is very similar.
import polars as pl
df_pl = pl.DataFrame(data)
# Rows where Age > 25, columns 'Name', 'Salary', 'Department'
high_age_pl = df_pl.filter(pl.col("Age") > 25).select(["Name", "Salary", "Department"])
print(high_age_pl)
Best Practices & Common Pitfalls
- Prefer
.loc[]with conditions and column names — more readable and safe - Use
.iloc[]only for positional slicing (first/last N rows/columns) - Boolean masks go in row position — column selection in second position
- Column lists must be in square brackets:
[['A', 'B']]not['A', 'B'] - Chain with
.query()for complex conditions — often cleaner than long masks - For huge data, prefer Polars filtering + selection — it's faster and more memory-efficient
Conclusion
Double slicing — rows and columns together with .loc[] or .iloc[] — is a core pandas skill that lets you filter and select exactly the data you need in one line. In 2026, prefer condition-based .loc[] for clarity and safety, use .iloc[] for positional tasks, and reach for Polars when performance matters. Master boolean masks, column lists, and chaining, and you'll manipulate DataFrames with speed and confidence.
Next time you need a filtered subset with specific columns — slice twice with .loc first.