Getting Started with Pandas: 5 Tricks That Save Hours
Data wrangling eats most of your project time. That's just the reality of data science work. But Pandas has tools that cut that time dramatically — and most tutorials never cover them.
Here are five that changed how I work.
Try it yourself — these two cells run real Python in your browser. Run the first one, then the second: it uses the df you just created.
1. pipe() for Readable Transformation Chains#
Instead of nesting functions or creating dozens of intermediate variables:
# The messy way
df2 = drop_duplicates(df)
df3 = fill_nulls(df2)
df4 = normalize_columns(df3)
result = filter_outliers(df4)Use pipe() to chain transformations cleanly:
result = (
df
.pipe(drop_duplicates)
.pipe(fill_nulls)
.pipe(normalize_columns)
.pipe(filter_outliers)
)Readable, debuggable, and each step is independently testable.
Each function in a pipe() chain receives the DataFrame as its first argument automatically. You can pass additional arguments using lambda functions.
2. query() for Expressive Filtering#
Stop writing boolean masks for every filter:
# Old way — hard to read at a glance
mask = (df['age'] > 25) & (df['salary'] < 80000) & (df['department'] == 'Engineering')
filtered = df[mask]# query() way — reads like English
filtered = df.query("age > 25 and salary < 80000 and department == 'Engineering'")You can even reference Python variables with @:
threshold = 50000
result = df.query("salary > @threshold")3. assign() for Non-Destructive Column Creation#
assign() returns a new DataFrame with added columns — perfect for chains:
result = (
df
.assign(
revenue_per_user=lambda x: x['revenue'] / x['users'],
is_profitable=lambda x: x['revenue'] > x['costs'],
log_revenue=lambda x: np.log1p(x['revenue'])
)
)assign() doesn't modify the original DataFrame. This makes your transformations safe to chain and easy to debug by inserting intermediate print() statements.
4. groupby() + transform() for Group-Level Features#
transform() is the missing link between groupby() and feature engineering:
# Add each user's average order value as a column (without collapsing the DataFrame)
df['user_avg_order'] = df.groupby('user_id')['order_value'].transform('mean')
df['orders_above_avg'] = df['order_value'] > df['user_avg_order']The result keeps the same shape as your original DataFrame — perfect for adding group statistics as features.
5. pd.cut() and pd.qcut() for Smart Binning#
Stop writing manual if-else logic for binning continuous variables:
# Equal-width bins
df['age_group'] = pd.cut(
df['age'],
bins=[0, 25, 35, 50, 100],
labels=['Gen Z', 'Millennial', 'Gen X', 'Boomer']
)
# Equal-frequency bins (quantile-based)
df['income_quartile'] = pd.qcut(
df['income'],
q=4,
labels=['Q1', 'Q2', 'Q3', 'Q4']
)qcut() is particularly useful when your data is skewed — it ensures each bin has roughly equal counts.
Wrapping Up#
These five aren't tricks for tricks' sake. Each one reduces cognitive load, makes your code more readable, and integrates better into pipelines. They're the kind of patterns that separate notebooks you can revisit in 6 months from notebooks you have to rewrite from scratch.
Next post: I'll cover pd.merge() edge cases that silently corrupt your datasets — and how to catch them before they cost you.