Every layer below this one is built on a table of numbers, and in the real world that table arrives broken: duplicate rows, three date formats in one column, -999 where a value should be, and "toronto", "Toronto " and "TORONTO" counted as three different cities. This is the unglamorous majority of the job — practitioners quote something like 80% of the time, and the order of operations genuinely matters. Generate 200 corrupted sales rows below, then watch each cleaning step explain why it has to happen when it happens.
The mess is generated by a seeded PRNG (mulberry32) so that the same seed always produces the same 200 broken rows — reproducibility is itself a data-cleaning discipline, since a bug you cannot regenerate is a bug you cannot fix. The pipeline then runs in a deliberate order: sentinels like -999 and "N/A" are converted to true nulls before any imputation, because otherwise those magic numbers get averaged into the replacement values and quietly poison the column. Text is trimmed and case-folded before anything is compared or grouped, since " toronto" and "Toronto" are equal to a human and not to a computer. Missing prices are filled with the per-product median rather than the mean, so a single fat-fingered order cannot drag the fill value around. Deduplication happens on the business key — the order id — not on whole rows, because two records of the same order that differ by one stray space are still one order.