Don't paper over nulls; understand them first
The instinct "I have nulls, let me fill them with the mean / 0 / forward-fill" is the most common bad reflex in data work. Nulls always carry information — they're either missing because the field doesn't apply, missing because the source didn't record it, or missing because of a bug. Each origin needs a different response, and "fill with mean" is almost never the right one.
Four legitimate strategies
- Drop the row — when the row is unusable without the field.
df.dropna(subset=['order_id', 'amount_usd']). - Drop the column — when the field is mostly null and removing it doesn't lose information.
- Impute with a sentinel — explicit
'unknown',-1, or a domain default — when downstream logic needs a value but the missingness is meaningful. - Impute with statistics — mean/median/forward-fill — only when the field is genuinely interchangeable across rows. Rare in practice; often masks bugs.
Outliers — same discipline
Outliers can be (a) data-entry errors (amount = 99999999 instead of 9999.99), (b) legitimate but unusual values, or (c) the entire signal you're trying to detect (fraud, anomalies). Don't auto-cap or auto-remove them. Surface them, count them, and decide per pipeline what they mean.