pandas: Indexing, Selection & GroupBy
Selection & Filtering
# Column selection
df['name'] # Series
df[['name', 'salary']] # DataFrame (list of columns)
# Row selection by position (iloc)
df.iloc[0] # first row as Series
df.iloc[0:5] # first 5 rows
df.iloc[:, 0:2] # all rows, first 2 columns
df.iloc[[0, 2, 4]] # specific rows
df.iloc[0, 1] # row 0, col 1 (scalar)
# Row selection by label (loc)
df.loc[0] # row with index label 0
df.loc[0:5] # rows 0–5 inclusive (label-based!)
df.loc[0, 'salary'] # specific cell
df.loc[[0, 2], ['name', 'salary']] # specific rows and columns
# Boolean filtering
df[df['salary'] > 60000]
df[(df['salary'] > 60000) & (df['age'] < 35)]
df[(df['dept'] == 'Engineering') | (df['dept'] == 'Design')]
df[df['status'].isin(['active', 'pending'])]
df[~df['name'].str.contains('Alice')] # negate
# query() — readable string-based filtering
df.query('salary > 60000 and age < 35')
df.query('dept in ["Engineering", "Design"]')
df.query('name == @name_variable') # use variable with @
# where / mask
df.where(df > 0, other=0) # keep values > 0, replace rest with 0
df.mask(df > 0, other=np.nan) # replace values > 0 with NaNApply & Vectorized Operations
# apply — row or column-wise (slow; prefer vectorized)
df['grade'] = df['score'].apply(lambda x: 'A' if x >= 90 else 'B' if x >= 80 else 'C')
df['full_name'] = df.apply(lambda row: f"{row['first']} {row['last']}", axis=1)
# map — element-wise on Series
df['dept_code'] = df['dept'].map({'Engineering': 'ENG', 'Design': 'DES'})
# Vectorized string operations (.str)
df['name'].str.upper()
df['name'].str.lower()
df['email'].str.split('@').str[1] # domain
df['name'].str.startswith('A')
df['desc'].str.contains('python', case=False, na=False)
df['name'].str.strip()
df['phone'].str.replace(r'[^0-9]', '', regex=True)
df['name'].str.len()
# Date operations (.dt)
df['date'] = pd.to_datetime(df['date'])
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month
df['day_of_week'] = df['date'].dt.day_name()
df['days_since'] = (pd.Timestamp.now() - df['date']).dt.daysGroupBy & Aggregation
# GroupBy basics
grouped = df.groupby('dept')
grouped['salary'].mean() # mean salary per dept
grouped['salary'].agg(['mean', 'min', 'max', 'count'])
# Multiple columns
df.groupby(['dept', 'level'])['salary'].mean()
# agg with different functions per column
df.groupby('dept').agg({
'salary': ['mean', 'sum'],
'age': 'mean',
'name': 'count',
})
# Named aggregations (pandas 0.25+)
df.groupby('dept').agg(
avg_salary=('salary', 'mean'),
total_salary=('salary', 'sum'),
headcount=('name', 'count'),
max_age=('age', 'max'),
)
# Custom aggregation
df.groupby('dept')['salary'].agg(lambda x: x.quantile(0.9)) # 90th percentile
# transform — broadcast result back to original index
df['dept_avg_salary'] = df.groupby('dept')['salary'].transform('mean')
df['salary_deviation'] = df['salary'] - df['dept_avg_salary']
# filter — keep groups satisfying a condition
df.groupby('dept').filter(lambda x: x['salary'].mean() > 70000)
# Pivot table
pd.pivot_table(df,
values='salary',
index='dept',
columns='level',
aggfunc='mean',
fill_value=0,
)
# crosstab
pd.crosstab(df['dept'], df['gender'], margins=True)Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free