Data Analyst Professional · Модуль 6 · Урок 20 із 51
Пропуски, дублікати й аномалії: рішення без втрати доказів
NULL, blank, duplicate та outlier — це сигнал, а не автоматична команда «видалити». Спочатку визначте причину, бізнес-сенс і вплив; потім оберіть quarantine, correction, imputation, exclusion або прийняття з disclosure.
Missingness має різні причини
| Стан | Приклад | Безпечне рішення |
|---|---|---|
| not applicable | refund_reason для paid | залишити NULL і задокументувати |
| not collected | старий source не мав region | позначити source/version |
| collection error | обов’язковий customer_ref відсутній | quarantine + upstream fix |
| unknown | немає доказу причини | не вигадувати value; disclosure |
COALESCE не «виправляє» якість. Підстановка zero або “unknown” змінює значення метрики і допустима лише за визначеним правилом.
Дублікати: спочатку ключ і survivorship
SELECT source_system, customer_ref, event_ts_text, amount_text,
COUNT(*) AS duplicate_rows,
ARRAY_AGG(source_row_id ORDER BY source_row_id) AS evidence_rows
FROM seowork_lab.raw_customer_events
GROUP BY 1,2,3,4
HAVING COUNT(*) > 1;Exact row duplicate, duplicate business key і кілька законних events — різні випадки. Для dedup задайте match key, winner rule, tie-breaker і збережіть rejected rows у quarantine з reason code.
ROW_NUMBER() OVER (
PARTITION BY source_system, normalized_customer_ref, parsed_event_ts, parsed_amount
ORDER BY loaded_at DESC, source_row_id DESC
) AS survivor_rankАномалія не дорівнює помилці
Impossible date, negative amount за забороненим rule, status поза dictionary.
Рідкісне, але можливе значення; потрібен контекст і robust method.
VIP order або разова акція; не видаляти без owner.
Стрибок після release/source change; потрібен incident і upstream fix.
Для skewed distributions median/IQR або percentile rules часто кращі за довільний average ± threshold. Outlier flag має бути окремим полем, а raw value — збереженим.
Quarantine pattern
CREATE TABLE clean_events AS
SELECT *,
CASE
WHEN customer_ref IS NULL OR BTRIM(customer_ref) = '' THEN 'MISSING_KEY'
WHEN status_text NOT IN ('paid','cancelled','refunded') THEN 'INVALID_STATUS'
ELSE NULL
END AS rejection_reason
FROM seowork_lab.raw_customer_events;-- valid scope: rejection_reason IS NULL
-- quarantine: rejection_reason IS NOT NULLУ production краще не змішувати clean і quarantine фізично без чіткого доступу, але навчальний pattern показує головне: кожна втрата рядка має причину та count.
Практика
- Порахуйте NULL окремо від blank/whitespace.
- Знайдіть exact і business-key duplicates.
- Запропонуйте deterministic survivorship rule.
- Позначте hard-invalid і suspicious rows, не перезаписуючи raw.
- Звірте raw = accepted + quarantined за rows і control amounts.
Офіційні джерела
Готовність до тесту
Ви не плутаєте missing reasons, визначаєте duplicate через grain/key, відділяєте anomaly від error і зберігаєте audit trail через quarantine.
Закріпіть матеріал уроку
Три сценарні питання. Для зарахування уроку потрібно дати щонайменше дві правильні відповіді.