Back to Data Analysis
Data Analysis · Cheat Sheet
Transforming Data
Tip: Use your browser's print function (Ctrl+P / Cmd+P) to save as PDF for offline study.
Transforming Cheatsheet
Filters are definitions
- Every filter asserts a business definition — state it next to the number: "Active users (logged in within 30 days): 41,200"
- Two dashboards disagree? Compare their
WHEREclauses before blaming the data - Every literal — a threshold, date, status, or country list — is a decision with an author. If you can't name the author, it's unaudited. (AI-generated code invents plausible literals fluently.)
- Mutable attributes (status, plan, segment) filtered at current value answer a question about today, not the past — historical questions need as-of snapshots
Unit traps
| Trap | Symptom | Check |
|---|---|---|
| Cents vs dollars | Off by 100x | Reconcile one day vs the finance dashboard |
| UTC vs local midnight | Daily numbers never reconcile; spikes on wrong day | Ask "whose midnight?" for every date filter |
| Fraction vs percentage | 0.15 vs 15 → negative prices | Min/max of the column settles it |
Row-count audit trail
Log COUNT(*) after every step; every drop is a checkable claim:
load: 84,210 → Q1 filter: 22,530 → join customers: 22,530 (no fan-out)
→ US: 15,771 (70%, matches mix) → active: 9,006 (−43%?! investigate)
Aggregation
- Group-by changes the grain — restate what one output row means
- Pick the function by the question:
SUM= magnitude,COUNT(*)= volume,COUNT(DISTINCT)= reach,AVG= intensity AVG/COUNT(col)skip NULLs — each group's mean may have a different denominator than its row count- Missing groups produce no rows, not zero rows — outer-join onto a complete group list when completeness matters; check the group count (24 months expected, 23 returned?)
- Reconcile: group totals must sum to the ungrouped total (gap = NULL keys)
The average-of-averages rule
Never average rates or averages. Aggregate ratios as sum(numerator) / sum(denominator).
| Segment | Visitors | Conversions | Rate |
|---|---|---|---|
| Organic | 10,000 | 500 | 5.0% |
| Paid | 1,000 | 100 | 10.0% |
- Wrong: (5% + 10%) / 2 = 7.5%
- Right: 600 / 11,000 = 5.45%
- Summary tables must store numerators AND denominators — bare rates cannot be rolled up
- Equal-weighting groups ("the average store") is a different question — legitimate only if stated
Joins
- Join type = which rows survive: inner drops unmatched (and your guest checkouts); default to left-join from the table that defines the metric
- One-to-many = fan-out: each left row duplicated once per match; sums inflate by exactly the duplication
- Fix: pre-aggregate the many side to the join-key grain before joining
- pandas guard:
pd.merge(..., validate='many_to_one')— declare your cardinality assumption - Anti-join ("who didn't"):
LEFT JOIN ... WHERE right.key IS NULL, orNOT EXISTS(avoidNOT INwith NULLs)
Join checks (non-negotiable)
- Row count before vs after — any increase after a left join = fan-out
- Right-side key uniqueness:
GROUP BY key HAVING COUNT(*) > 1 - Known total reconciles: revenue in = revenue out
- Match rate sane — a low match rate is usually a key-format bug (
'CUST-001'vs'cust-001', int vs zero-padded string, timestamp vs date), not a finding
Aligned to the pandas documentation and the practical data-analysis canon.
Make this cheat sheet yours
Personalize this sheet — focus it however you study, or build one from the exact questions you keep getting wrong.
Sign up free to create a personalized cheat sheet.