Тобі передали файл із дошки оголошень про вживані телефони: 1 212 рядків, вісім стовпців, супровідний лист на три речення. «Ціна в гривнях, памʼять у гігабайтах, остання колонка — чи виявилось оголошення шахрайським». Файл відкривається, помилок немає, усе на місці. Здається, можна працювати.
Не можна. У цій таблиці зараз лежать: 101 порожня ціна, причому порожня не випадково; 12 рядків, які просто продубльовані; стовпець із памʼяттю, який pandas прочитав як текст; шість оголошень дорожчих за 70 000 грн, з яких частина справжня, а частина — одруки; і один стовпець, звʼязаний із відповіддю настільки добре, що ним хочеться одразу скористатись — і саме тому не можна.
Нічого з цього не видно з опису файлу. Усе це видно за пʼятнадцять хвилин, якщо знати, куди дивитись. Це і є розвідувальний аналіз даних (exploratory data analysis, EDA) — і ця тема саме про нього.
01 / МотивДані не такі, як їх описали
У темі 02 ми домовились, що навчання з учителем — це таблиця з ознаками й таргетом. Тоді таблиця була ідеалізована: рівні стовпці, охайні числа. У житті вона така майже ніколи, і причин рівно три.
Дані збирали не для тебе. Колонку «стан телефона» заповнює продавець у вікні з випадним списком — і половина вибирає перший пункт, бо швидше. Колонку «скарг» проставляє служба підтримки. Ніхто з них не думав про майбутню модель.
Дані зберігали через кілька систем. Числа проходять через експорт у таблицю, вивантаження у файл, читання назад — і на кожному кроці «128» може перетворитись на «128 ГБ», а порожнє поле — на текст «немає».
Дані змінювались у часі. Торік поле «памʼять» було вільним текстом, цього року стало списком. У файлі лежать обидва варіанти, і ніхто про це не напише.
Тому розвідка — не етап звітності, а страховка, і головний її аргумент — ціна помилки. Дірку в даних, помічену зараз, ти виправляєш за годину. Ту саму дірку, помічену після навчання моделі, ти виправляєш разом з усім, що встиг на ній побудувати: обробкою, ознаками, поділом на навчальну й тестову частини, висновками, які вже комусь показав. Звідси настрій теми, майже неввічливий: ми шукаємо неприємності, поки вони дешеві.
Уся тема — на одній таблиці. Ось вона.
| стовпець | що це | тип |
|---|---|---|
| модель | назва телефона, шість різних моделей | текст |
| рік | рік випуску, від 2017 до 2024 | ціле |
| стан | нове, дуже добре, добре, задовільне | текст |
| памʼять_гб | обсяг памʼяті: 64, 128, 256 або 512 | ? |
| вік_акаунта | скільки днів існує акаунт продавця | ціле |
| скарг | скільки скарг надійшло на це оголошення | ціле |
| ціна | ціна в оголошенні, гривень | дробове |
| шахрайське | таргет: 1 — оголошення виявилось шахрайським | 0 або 1 |
Знак питання в третьому рядку не помилка верстки. Це те, що ми зараз побачимо.
DataFrame,
Series, читання файлів, loc і iloc, фільтр умовою,
groupby, fillna — ми розібрали в
темі 34 курсу Python. Тут ми жодного
разу не пояснюємо, як викликати метод. Ми говоримо лише про те, що читати
в його відповіді. Графіки — на matplotlib
з теми 35.02 / ОглядПерший погляд: пʼять команд
Перше знайомство з будь-якою таблицею — це пʼять викликів. Вони завжди ті самі, і робити їх треба навіть тоді (особливо тоді), коли ти впевнений, що знаєш, що всередині. Цінність не в командах, а в питаннях, які до кожної з них поставлені.
shape — чи стільки рядків, скільки я очікував. Наша
таблиця дає (1212, 8). Якщо в листі було сказано «вивантаження за рік, близько
тисячі оголошень» — усе гаразд. Якщо було сказано «40 тисяч» — далі можна не дивитись,
спершу треба розібратись, куди поділись 39 тисяч рядків. Це найдешевша перевірка з усіх
і найчастіше пропущена.
head() — чи значення схожі на те, що обіцяє назва стовпця.
Не «які тут числа», а саме це. У нашій таблиці другий рядок одразу показує NaN
у стані, а четвертий — памʼять, записану як 256 ГБ. Обидві дрібниці видно
неозброєним оком у перших пʼятьох рядках, і обидві коштуватимуть годину, якщо їх не
помітити.
dtypes — чи всі числові стовпці справді числові. Ось що
віддає наша таблиця:
object у pandas означає «щось, що я не зміг звести до числа» — зазвичай
текст. Для «моделі» й «стану» це нормально, для «памʼять_гб» — тривожний знак. Тип не
буває «майже правильним»: досить одного нечислового значення, щоб уся
колонка стала текстом. Тобто object у числовій колонці — це не властивість
даних, а слід події: десь у файлі є рядок, який випадає із загального правила.
У нас таких рядків 215 із 1212: у них памʼять записана як 128 ГБ замість
128. І тут ховається справжня пастка. Найочевидніша реакція — «зведімо
колонку до чисел» — виглядає так:
errors="coerce" означає «те, що не зміг прочитати, зроби пропуском». Ця
команда не падає, не попереджає й нічого не пише в консоль. Вона просто мовчки перетворює
215 цілком справжніх значень на порожнечу — сьома частина таблиці. Правильна дія — спершу
прибрати суфікс, і лише потім переводити в число:
info() — де дірки. Він друкує для кожного стовпця
кількість непорожніх значень, і її треба порівнювати з першим рядком виводу. У нас
1212 entries, а в колонці «ціна» стоїть 1111 non-null — отже,
101 порожня. У колонці «стан» — 1164, отже 48 порожніх. Решта стовпців повні.
describe() — чи числа взагалі бувають такими. Його читають
не зверху вниз, а трьома парами рядків. Ось вивід для ціни:
Пара перша: count проти кількості рядків. Різниця — це
пропуски, і вона тут є.
Пара друга: min і max проти здорового глузду.
Не «чи це можливо в принципі», а «чи буває таке на дошці вживаних телефонів». 130 грн —
буває, це майже брухт. 95 000 грн теж буває, але на ці рядки доведеться подивитись окремо.
Пара третя: mean проти 50 %. Середнє 6 509,
медіана 4 010. Коли ці два числа розходяться в півтора раза, у даних або довгий хвіст,
або кілька дуже великих значень, або помилки введення. У нас, як зʼясується, всі три.
І шоста команда, яку варто дописати до цих пʼятьох: duplicated().sum().
Вона дає 12. Дванадцять рядків у таблиці повторюються повністю, до
останнього символу. Найчастіша причина — оголошення подали двічі або вивантаження
злилося з двох файлів. Дублікати не ламають нічого одразу, але вони тихо збільшують вагу
тих самих обʼєктів у будь-яких підрахунках.
Таблиця 1 · Що бачу у виводі → про що це говорить
Ліва колонка — те, що буквально надруковано на екрані. Права — гіпотеза, яку через це треба перевірити. Не діагноз: жоден із цих рядків не є вироком, кожен є приводом подивитись уважніше.
| бачу | про що це говорить | що зробити |
|---|---|---|
Числовий стовпець має тип object | десь є нечислове значення — суфікс, пробіл між тисячами, кома замість крапки, слово «немає» | подивитись на унікальні значення, розібрати текст, лише потім переводити в число |
count менший за кількість рядків | у стовпці є пропуски | зʼясувати, у яких саме рядках, і чи це випадково |
| Середнє помітно більше за медіану | розподіл скошений праворуч, є довгий хвіст | дивитись на медіану, а не на середнє; побудувати гістограму |
std більше за mean | розкид величезний, у стовпці змішані різні за природою обʼєкти | розділити за категорією і порахувати окремо |
min дорівнює нулю там, де нуль неможливий | нулем позначили відсутність значення | замінити нулі на NaN перед будь-якими підрахунками |
max у сотні разів більший за медіану | або справжній рідкісний обʼєкт, або зайвий нуль при введенні | подивитись на ці рядки цілком, з усіма стовпцями |
| Кількість унікальних значень дорівнює кількості рядків | це ідентифікатор, а не ознака | прибрати зі списку ознак |
duplicated().sum() більше нуля | рядки повторюються повністю | зрозуміти, звідки повтори, перш ніж їх прибирати |
03 / ПропускиПропуски: скільки, де і чому
Порахувати пропуски вміє один рядок: дошка.isna().sum(). У нас 101 у
ціні й 48 у стані. Це відповідь на питання «скільки» — і саме тут більшість зупиняється.
А найважливіше питання інше: чому саме ці рядки.
Річ у тім, що пропуск буває трьох дуже різних сортів, і плутати їх дорого.
- Випадковий. Значення зникло без звʼязку з чим завгодно — збій запису, людина проґавила поле. Такі пропуски найбезпечніші: заповнення їх майже не спотворює.
- Повʼязаний з іншими стовпцями. Наприклад, стан не вказують частіше для старих телефонів. Пропуск не випадковий, але його можна пояснити тим, що в таблиці вже є.
- Повʼязаний із самим значенням, якого немає. Ціну не вказують саме тоді, коли вона незручна. Це найгірший сорт: те, що зникло, зникло через себе саме, і в даних не лишилось нічого, чим це відновити.
Розрізнити їх можна простою перевіркою: порівняти рядки з пропуском і без нього за якимось третім стовпцем. Найцікавіший третій стовпець — таргет. Рахуємо частку шахрайських окремо в тих, у кого ціна вказана, і в тих, у кого ні:
| рядки | скільки | чесних | шахрайських | частка шахрайських |
|---|---|---|---|---|
| ціна вказана | 1 111 | 972 | 139 | 12.5 % |
| ціни немає | 101 | 44 | 57 | 56.4 % |
Різниця в чотири з половиною рази. Серед оголошень без ціни шахрайських більше половини, серед решти — восьма частина. Це вже не статистична дрібниця, це поведінка: шахрай не називає ціну, бо ціна — те місце, де його оголошення виглядає підозріло.
Звідси головний висновок розділу: сам факт пропуску буває ознакою. Не значення, якого немає, а те, що його немає. Технічно це один додатковий стовпець:
Порівняй це зі стовпцем «стан». Там пропусків 48, і частка шахрайських серед них 12.5 % проти 16.3 % у решті таблиці — різниця в межах випадковості на такій кількості рядків. Пропуск у стані ні про що не говорить; пропуск у ціні говорить майже все. Один рядок коду розрізняє ці випадки, і зробити його треба до того, як заповнювати дірки.
Схема 1 · Пропуск як ознака
Ті самі 1 212 рядків, поділені двічі: за пропуском ціни й за пропуском стану. Висота стовпчика — частка шахрайських оголошень у групі.
Способи заповнити дірки існують, і їх багато: середнє, медіана, найчастіше значення, значення сусіднього рядка, окрема категорія «невідомо», передбачення за іншими стовпцями. Вибір між ними — окрема розмова, і вона буде в темі про передобробку. Поки що досить двох правил. Перше: перш ніж заповнювати, перевір, чи пропуск випадковий — одним порівнянням, як щойно. Друге: заповнення середнім, зроблене не думаючи, — найпоширеніша помилка новачка. Воно не додає інформації, зате робить розподіл штучно вужчим і ховає той факт, що значення взагалі не було.
04 / ФормаФорма розподілу
describe() віддає сім чисел, і цього мало. Сім чисел не розрізняють
розподіл з одним піком і розподіл з двома, а це різні світи. Тому наступний крок після
таблиці — гістограма: вісь ціни ріжуть на однакові відрізки (кошики) і
рахують, скільки оголошень потрапило в кожен.
Гістограма має одну властивість, про яку мовчать: її висновок залежить від кількості кошиків. Це не тонкість для педантів — від цього залежить, що ти скажеш про дані вголос.
Інтерактив 1 · Скільки кошиків — стільки й висновків
Ціни з нашої таблиці, 1 111 оголошень із вказаною ціною. Вісь обрізана на 25 000 грн — вище лежать 33 оголошення, і про них окрема розмова в наступному розділі. Рожева лінія — середнє, бірюзова — медіана.
Форма, яку ми бачимо, зветься скошеною праворуч (right-skewed): пік зліва, довгий хвіст справа. Так виглядає майже все, що не буває відʼємним і має верхню межу лише теоретично — ціни, зарплати, час очікування, розмір міста. Протилежна форма, симетричний горбик, у природних даних трапляється рідше, ніж здається з підручників.
Саме скошеність розводить середнє й медіану, і це варто проговорити повільно, бо плутанина тут коштує дорого.
Середнє — сума всіх цін, поділена на кількість. Кожне оголошення вносить свою суму цілком: телефон за 95 000 грн важить у сумі стільки ж, скільки двадцять телефонів по 4 750 грн.
Медіана — значення, яке стоїть посередині відсортованого списку. Їй байдуже, наскільки велике найбільше число: важливо лише, що воно більше за середину.
Розрив у 1.62 раза. Перевіримо, звідки він: скільки оголошень дешевші за середнє?
Понад дві третини оголошень дешевші за «середнє оголошення». Отже, речення «середня ціна на дошці — 6 509 грн» описує обʼєкт, якого майже не буває: воно правдиве арифметично й хибне по суті. Речення «половина оголошень дешевша за 4 010 грн» описує саме те, що є.
Означає це не «медіана краща», а дещо точніше. Медіана відповідає на питання «яке оголошення типове». Середнє відповідає на питання «скільки грошей на дошці всього». Якщо тобі треба закупити партію телефонів — рахуй середнє, бо платити доведеться суму. Якщо треба сказати покупцеві, на що розраховувати, — кажи медіану. Помилка починається тоді, коли середнім відповідають на друге питання.
05 / ВикидиВикиди й межа
У хвості розподілу лежать викиди (outliers) — значення, які помітно відірвались від решти. Найпоширеніший спосіб їх позначити не потребує ніяких припущень про форму розподілу і зветься правилом міжквартильного розмаху. Порахуймо його руками на наших числах.
Квартилі — це три значення, що ділять відсортований список на
чотири рівні за кількістю частини. Нам потрібні перший і третій: нижче Q1
лежить чверть оголошень, нижче Q3 — три чверті.
describe() уже їх надрукував:
Це просто відстань між ними — ширина смуги, у якій живе середня половина оголошень. Позначають IQR (interquartile range).
Чому саме середня половина: вона не залежить від того, що коїться в хвостах. Хоч постав найдорожчий телефон у мільйон гривень — Q1 і Q3 не зрушать. Тобто лінійка, якою ми міряємо викиди, сама від викидів не залежить. Це і є вся ідея правила.
Від квартилів відкладають півтора розмаху в кожен бік:
нижня = 2 180 − 1.5 · 5 520 = −6 100
Нижня межа вийшла відʼємною, а ціна відʼємною не буває — отже, знизу викидів немає жодного. Усе цікаве вгорі: 78 оголошень дорожчі за 15 980 грн, це 7.0 % таблиці.
Множник 1.5 — домовленість, а не закон природи. Він зручний і поширений, але нічим не священний: на скошених даних, як наші, він завжди позначає багато рядків справа, бо припускає приблизну симетрію, якої тут немає. Тому корисно подивитись, як число викидів залежить від множника.
Інтерактив 2 · Де провести межу
Кожна риска внизу — одне оголошення. Зверху — «скринька»: прямокутник від Q₁ до Q₃, лінія посередині — медіана, вуса — до поточної межі. Оголошення за межею позначені рожевим.
І тепер найважливіше в цьому розділі. Викид — не синонім помилки. Правило міжквартильного розмаху не знає нічого про телефони; воно знає лише, що число велике. Подивімось на шість найдорожчих оголошень цілком, з усіма стовпцями:
| модель | рік | стан | памʼять | скарг | ціна |
|---|---|---|---|---|---|
| Gamma X | 2017 | нове | 512 | 0 | 95 000 |
| Gamma X | 2017 | нове | 512 | 0 | 91 000 |
| Gamma X | 2017 | нове | 512 | 0 | 88 000 |
| Beta 12 Pro | 2021 | добре | 256 | 0 | 83 500 |
| Gamma X | 2017 | нове | 512 | 0 | 82 000 |
| Gamma X Ultra | 2017 | добре | 256 | 0 | 76 000 |
Чотири рядки з шести — це та сама комбінація: Gamma X 2017 року, стан «нове», 512 гігабайтів. Запакований флагман семирічної давності, який ніколи не вмикали. За такі речі колекціонери платять, і 90 000 грн тут не помилка, а ринок. Прибрати ці рядки означає викинути справжнє явище, яке в даних є.
Два інші рядки — Beta 12 Pro у стані «добре» за 83 500 і Gamma X Ultra 2017 року за 76 000 — на тій самій висоті, але сусідні стовпці їх не підтримують. Телефон у стані «добре» не коштує як чотири нових. Це майже напевно зайвий нуль при введенні: 8 350 стало 83 500, 7 600 стало 76 000. Дві однакові за величиною ціни, і два протилежні рішення — причому розрізняє їх не ціна, а решта рядка.
І ще один наслідок, який видно тільки на числах. Викиди спотворюють не лише середнє — вони ламають підрахунки звʼязків. Для моделі Gamma X кореляція між роком випуску й ціною дорівнює 0.06: наче зв'язку немає взагалі. Прибираємо чотири колекційні рядки зі 122 — і та сама кореляція стає 0.80. Чотири рядки з півтори сотні перевернули висновок.
06 / ЗвʼязкиЗвʼязки між ознаками
Кожен стовпець ми подивились окремо. Тепер попарно: чи повʼязані вони між собою і чи повʼязані з таргетом. Стандартний інструмент — кореляція Пірсона, число від −1 до +1.
Словами вона означає ось що: наскільки добре хмару точок можна замінити однією прямою. +1 — точки лежать на прямій, що йде вгору. −1 — на прямій, що йде вниз. 0 — прямої, яка щось описує, немає. Одна команда рахує всі пари одразу:
| пара стовпців | кореляція | як це читати |
|---|---|---|
| скарг ↔ шахрайське | 0.887 | майже ідеальний звʼязок — і саме тому підозрілий |
| рік ↔ ціна | 0.249 | новіші дорожчі, але слабко |
| памʼять ↔ ціна | 0.209 | більше памʼяті — трохи дорожче |
| вік акаунта ↔ шахрайське | −0.101 | у шахраїв акаунти молодші |
| вік акаунта ↔ ціна | −0.030 | звʼязку немає |
| ціна ↔ шахрайське | −0.012 | звʼязку немає? |
Три рядки з шести варті окремої розмови — і кожен показує власну межу цього інструмента.
Рік і ціна: 0.249. Здається, вік телефона майже не впливає на ціну, що безглуздо. Причина в тому, що ми змішали шість різних моделей: Alfa A5 2024 року коштує дешевше за Gamma X Ultra 2017-го, і ця різниця забиває залежність від року. Візьмімо одну модель і лише чесні оголошення — Beta 12, 171 рядок — і порахуймо ту саму кореляцію: 0.840. Звʼязок був увесь час; кореляція по всій таблиці його не показала, бо всередині таблиці лежать шість різних ринків.
Ціна і шахрайство: −0.012. Практично нуль. Спокуса тут очевидна — викреслити ціну зі списку корисних ознак і піти далі. Це була б помилка, і ось чому. Порахуймо частку шахрайських окремо в кожній десятій частині цін, від найдешевших до найдорожчих:
| десята частина за ціною | межі, грн | частка шахрайських |
|---|---|---|
| найдешевші | до 1 230 | 42.9 % |
| друга | 1 230 – 1 820 | 18.9 % |
| третя | 1 820 – 2 510 | 12.6 % |
| середина | 4 010 – 5 060 | 2.7 % |
| девʼята | 9 040 – 13 550 | 7.2 % |
| найдорожчі | понад 13 550 | 18.0 % |
Від 42.9 % до 2.7 % і назад до 18.0 %. Звʼязок величезний — просто він не прямий, а U-подібний: підозрілі й дуже дешеві оголошення (приманка «неймовірна знижка»), і дуже дорогі (виманити велику передоплату). Пряма, проведена крізь таку хмару, лежить горизонтально, і кореляція чесно повідомляє нуль. Вона не помилилась — вона відповіла на своє питання, а ми поставили інше.
Інтерактив 3 · Кореляція проти звʼязку
Пʼять пар стовпців із нашої таблиці. Точки — оголошення; вісь цін обрізана, найдорожчі оголошення в кадр не потрапляють. Жирна ламана — типове значення по вертикальній осі всередині кожної десятої частини за горизонтальною: медіана ціни, а для колонки з нулів і одиниць — частка одиниць. Там, де вертикальна вісь двійкова, точки трохи розсунуті, щоб не злипались.
Звідси практичне правило: нульова кореляція означає «прямої немає», а не «звʼязку немає». Перш ніж викреслювати ознаку через маленьке число, подивись на неї очима або порахуй середнє таргета по кошиках — це десять рядків коду й одна хвилина.
Скарги і шахрайство: 0.887. Третій рядок, і найважчий. Почнімо з загального: кореляція не означає причину. Це фраза, яку всі чули й майже ніхто не застосовує, тож ось вона на нашій дошці.
Скарги й шахрайство рухаються разом — але скарга не робить оголошення шахрайським. Причина йде у зворотний бік: оголошення було шахрайським, тому люди й поскаржились. Той самий фокус із памʼяттю та ціною: більша памʼять корелює з вищою ціною, але значна частина цієї кореляції — не про памʼять, а про те, що моделі з великою памʼяттю в принципі дорожчі. Кореляція бачить, що дві величини рухаються разом, і не бачить, хто кого рухає — та чи не рухає їх обидві щось третє.
07 / ТаргетПогляд на таргет
Окремо й уважно варто подивитись на сам таргет — стовпець, який ми збираємось передбачати. Питання тут два: скільки в нього класів і чи рівні вони за розміром.
Класи нерівні: на кожне шахрайське оголошення припадає пʼять чесних. Це називають дисбалансом класів, і він тут не крайній — буває й один до тисячі. Але навіть таке співвідношення вже змінює все, що ми знаємо про вимірювання якості.
Згадай тему 05. Модель, яка не дивиться на ознаки взагалі й називає чесними геть усі оголошення, вгадає в 83.8 % випадків. Виглядає це як пристойний результат — і при цьому шахраїв упіймано рівно нуль. Саме тому дисбаланс треба знати до того, як обрана метрика: він визначає, з чим взагалі порівнювати будь-яке майбутнє число. Precision і recall ставлять правильні питання — скільки з упійманих справді шахраї і скільки шахраїв упіймано, — а частка правильних відповідей на нерівних класах просто бреше.
Другий погляд на таргет — розподіл ознак усередині кожного класу. Найкорисніше порівняння в нашій таблиці таке:
| група | оголошень | медіанна ціна |
|---|---|---|
| чесні | 1 016 | 4 235 грн |
| шахрайські | 196 | 1 940 грн |
Медіанне шахрайське оголошення вдвічі дешевше за медіанне чесне. Але ми вже знаємо, що цим справа не вичерпується: серед найдорожчої десятої частини шахрайських теж 18 %. Тобто одне число («шахраї дешевші») правдиве й недостатнє — і зловити це вдалось лише тому, що ми подивились на розподіл, а не на середнє.
Заодно з таргетом варто перевірити ще одну річ — чи не змінюється частка класів у часі. Якщо у вивантаженні за перше півріччя шахрайських 8 %, а за друге 24 %, то це вже не одна задача, а дві, і будь-який поділ на навчальну й тестову частини треба робити з оглядкою на дату.
08 / ВитікВитік даних
Повернімось до першого рядка таблиці кореляцій. Скарги повʼязані з таргетом на 0.887 — це надзвичайно багато. Подивімось на цю пару впритул:
| чесних | шахрайських | |
|---|---|---|
| скарг немає | 994 | 0 |
| скарг ≥ 1 | 22 | 196 |
Правило «якщо є хоч одна скарга — оголошення шахрайське» ловить усі 196 шахрайських оголошень і помиляється лише на 22 чесних. Точність такого правила — 89.9 % серед позначених, і жодного пропущеного шахрая. Одна колонка, жодного навчання, майже ідеальний результат.
Це не удача. Це витік даних (data leakage) — ситуація, коли в ознаки потрапила інформація, якої в момент передбачення ще не існує.
Подумай, коли зʼявляється скарга. Оголошення публікують — скарг нуль. Хтось надсилає передоплату й не отримує телефон — надходить скарга. Служба підтримки розбирається й ставить мітку «шахрайське». Тобто скарга і мітка зʼявляються в один і той самий момент і з однієї й тієї самої події. Модель, навчена на скаргах, у робочому режимі отримає нове оголошення, у якого скарг нуль завжди — і назве чесними всі. Її чудова якість на історичних даних не переживе першого ж дня.
Схема 2 · Чому «скарг» не можна брати в ознаки
Вісь часу одного оголошення. Угорі — момент, у який модель має дати відповідь. Унизу — момент, у який зʼявляється значення в колонці «скарг».
Витік підступний саме тим, що зовні виглядає як успіх. Він не дає помилки, не пише попереджень і не псує метрику — він її покращує. Тому в роботі з даними діє правило, яке варто вивчити напамʼять:
Розвідка ловить витік краще за будь-яку іншу перевірку — і ловить його рано, до навчання, коли виправлення коштує один рядок. Три сигнали, за якими його видно:
- Аномально висока кореляція з таргетом. Значення понад 0.8 у справжній задачі трапляється рідко. Наші 0.887 — саме такий випадок.
- Ознака, яка виглядає як наслідок, а не причина. Скарги, повернення, статус «заблоковано», дата закриття — усе це описує те, що вже сталося.
- Ідеальний поділ у таблиці спряженості. Нуль у клітинці «чесні зі скаргами» був би вироком; у нас там 22, і це майже так само підозріло.
Що з цим робити? Викинути колонку «скарг» зі списку ознак — і не з таблиці. Вона чудово годиться для аналізу заднім числом («скільки шахрайських оголошень ми пропустили до першої скарги»), просто не годиться для передбачення. Це той самий принцип, що й у темі 03: усе, що модель бачить під час навчання, має бути доступним і в момент застосування — інакше вимірювання не має сенсу. І це продовження розмови з теми 02 про те, чим ознака відрізняється від відповіді, записаної іншими словами.
09 / ПідсумокЧекліст розвідки
Зберімо всю тему в послідовність, яку можна виконати механічно на будь-якій новій таблиці. Порядок не випадковий: кожен крок спирається на попередній, і кожен наступний дорожчий.
Схема 3 · Чекліст розвідки даних
Пʼятнадцять пунктів, приблизно пʼятнадцять хвилин. Праворуч — те, на що дивитись у відповіді.
corr(), а рятує від тижня роботи над моделлю, яка ніколи не
запрацює. Пункти 1–4 роблять на будь-якій таблиці взагалі; 5–10 — на кожному
числовому стовпці, який планується в ознаки.Одна вимога, яка не вміщається в чекліст, але важливіша за половину його пунктів: записуй, що знайшов. Не в памʼять, а текстом — прямо в зошит, поруч із кодом. Через два тижні ти не згадаєш, чому в колонці ціни зʼявився стовпець «ціни_немає» і чому «скарг» немає серед ознак. А той, хто відкриє твій зошит замість тебе, не згадає й поготів.
10 / ДаліЩо далі
Ми пройшли таблицю наскрізь і жодного разу нічого в ній не змінили. Це не випадковість і не економія — це порядок дій. Спершу дивимось, потім вирішуємо. Ось із чим ми виходимо з цієї таблиці:
- 12 дублікатів — зрозуміти походження, найімовірніше прибрати;
- стовпець памʼяті потребує розбору тексту, інакше 215 значень зникнуть мовчки;
- 101 пропуск у ціні — не випадковий, потрібна окрема колонка «ціни_немає»;
- 48 пропусків у стані — випадкові, можна заповнювати;
- 78 викидів за правилом 1.5·IQR, з яких щонайменше два — одруки, а чотири — справжні колекційні телефони;
- ціна повʼязана з таргетом U-подібно, тому лінійні прикидки на ній працюватимуть погано;
- колонка «скарг» — витік, зі списку ознак прибрати.
Кожен пункт цього списку — завдання для передобробки: наступної теми, де ми навчимось прибирати дублікати без втрати сенсу, заповнювати пропуски свідомо, кодувати текстові колонки числами й приводити ознаки до спільного масштабу. А тема після неї — інженерія ознак: там із тієї самої таблиці зʼявляться нові стовпці, і U-подібний звʼязок ціни з таргетом перестане бути проблемою.
Але головне з цієї теми не залежить від жодної наступної. Таблиця, яку тобі дали, — не факт, а чиясь розповідь про факти. Перевіряти цю розповідь треба до того, як на ній щось будувати. Пʼятнадцять хвилин зараз — це те, що не доведеться переробляти місяць потому.
practice.ipynb ти збереш ту саму
дошку оголошень із нуля, пройдеш перший погляд крок за кроком, знайдеш пропуски й
перевіриш, чи вони випадкові, побудуєш гістограми з різною кількістю кошиків, порахуєш
викиди за міжквартильним розмахом, побудуєш кореляційну матрицю — і викриєш витік, який
у ній ховається.Далі в темі
Теорію прочитано. Тепер закріпи її на практиці.