Двадцять питань

Дерево рішень не рахує відстані й не множить матриці. Воно просто ставить питання — одне за одним, і кожне наступне залежить від відповіді на попереднє.

У грі «двадцять питань» один гравець загадує предмет, а другий має його вгадати, ставлячи запитання, на які можна відповісти лише «так» або «ні». Хороший гравець ніколи не питає навмання. Він починає з питання, яке ділить світ навпіл: «це жива істота?». Кожна відповідь відрізає половину варіантів, і за двадцять кроків можна дійти до мільйона предметів.

Дерево рішень — це та сама гра, тільки питання ставить алгоритм, а загаданий предмет — відповідь для конкретного обʼєкта. Модель складається з вузлів рішення (питання про одну ознаку), гілок (відповіді «так» і «ні») та листків (готовий прогноз). Навчити дерево — це підібрати самі питання і їхній порядок так, щоб дійти до впевненої відповіді за якнайменше кроків.

Уся лекція побудована навколо однієї задачі. Банк хоче знати, чи залишиться клієнт із ним на наступний рік. Про кожного клієнта відомі лише два числа: стаж — скільки місяців він уже обслуговується, і витрати — скільки в середньому тисяч гривень проходить через його картку щомісяця. Двовимірна задача зручна тим, що модель можна намалювати цілком: усе, що дерево «думає», видно на площині.

ІдеяМодель, яку можна прочитати вголос

Почнімо з кінця — подивімось на готову модель. Кожне питання дерева має вигляд «ознака ≤ поріг». Питання про стаж проводить на площині вертикальну лінію, питання про витрати — горизонтальну. Кожна лінія розрізає прямокутник, у якому ми зараз перебуваємо, на два менші прямокутники. Після всіх розрізів площина розпадається на набір прямокутних клітин, і в кожній клітині дерево дає одну й ту саму відповідь.

Таку модель називають кусково-сталою: «стала» — бо всередині однієї плитки відповідь не змінюється зовсім, «кусково» — бо плиток багато й на межі між ними відповідь стрибає. Пряма лінія в лінійній регресії змінює прогноз потроху з кожним кроком ознаки; дерево тримає прогноз незмінним, а потім різко перемикає його. Порухай повзунок глибини й подивись, як плиток стає більше:

Як дерево ріже площину

Глибина — це максимальна кількість питань поспіль. Пунктир — справжня межа, за якою генерувались дані.

точність train—
точність test—
листків—
найкраща test—
Що читати: насиченість плитки — впевненість листка. Бліда плитка означає, що в цьому прямокутнику класи майже порівну і дерево вгадує ледь краще за монетку. Глибина 0 — дерево без жодного питання: одна відповідь на всіх.

Зверни увагу на дві речі. По-перше, при глибині 0 модель вироджується в константу — вона завжди називає більший клас незалежно від того, що їй показали. Це нижня межа, з якою порівнюють будь-яке дерево: у нашій навчальній вибірці 103 клієнти лишились і 97 пішли, тож відповідь «лишиться» всім підряд дає 51.5% влучань на навчальних даних. Будь-яке дерево, що не побило це число, не навчилось нічого. По-друге, при великій глибині зʼявляються крихітні плитки навколо окремих точок: дерево виділяє під один-єдиний обʼєкт власну кімнату. Це вже перенавчання, і до нього ми ще повернемось окремо.

Що насправді лежить у листку

Листок — не просто напис «лишиться». Усередині записано, скільки навчальних обʼєктів у нього потрапило і як вони розподілились між класами. Наприклад, один із листків нашого дерева зберігає пару «54 лишились, 4 пішли». З цієї пари беруть дві речі:

Звідси й насиченість плиток на малюнку вище: чим ближча частка до 0 або до 1, тим яскравіша плитка. Бліда плитка — це листок, у якому класи майже порівну, і дерево там чесно зізнається, що не знає відповіді. Ось чому дерево вміє не лише відповідати, а й показувати, наскільки воно впевнене, — і робить це без жодної додаткової формули.

І ще одне, що корисно засвоїти одразу: дерево нічого не памʼятає про самі обʼєкти. Після навчання від 200 клієнтів лишається тільки набір питань і кілька пар чисел у листках. Тому прогноз коштує кілька порівнянь, а вся модель уміщається на аркуші паперу.

ГеометріяЧому розрізи перпендикулярні осям

Питання дерева завжди стосується однієї ознаки: «витрати ≤ 4.7?». Воно ніколи не має вигляду «0.3·стаж + 0.7·витрати ≤ 5». Причина суто обчислювальна. Щоб перебрати всі пороги за однією ознакою, достатньо відсортувати обʼєкти й пройти список — це десятки операцій. Щоб перебрати всі можливі нахилені площини, треба шукати в неперервному багатовимірному просторі напрямків, а це вже окрема задача оптимізації всередині кожного вузла.

Наслідок такий: межа рішень дерева завжди складається з відрізків, паралельних осям. Якщо справжня межа в даних теж «прямокутна» — дерево влучає в неї майже точно. А якщо справжня межа діагональна, дерево змушене будувати сходинки: багато дрібних розрізів, які наближають пряму ламаною лінією.

Ціна сходинок — не абстракція. Кожна сходинка зʼїдає один вузол, а вузол ділить дані навпіл. Отже після трьох сходинок у кожній комірці лишається ввосьмеро менше обʼєктів, ніж було, і наступні рішення дерево ухвалює з жменьки точок — тобто з шуму. Дерево витрачає свій бюджет складності не на структуру задачі, а на апроксимацію нахилу.

У наступному інтерактиві дані ті самі — просто повернуті. Логістична регресія на них працювала б однаково добре під будь-яким кутом. Дерево — ні:

Та сама задача, повернута на кут

Справжня межа — одна пряма (пунктир). Повертаємо дані й дивимось, що робить дерево фіксованої глибини 3.

точність test—
листків—
стеля: пряма під тим самим кутом—
Висновок: дерево не інваріантне до повороту системи координат. Тому вдалий вибір ознак для дерева важить більше, ніж для лінійних моделей: ознака «різниця двох величин» може замінити десяток сходинок.

Заміряно на цих самих даних, дерево глибини 3: при куті 0° воно дає 94.6% на тесті, а стеля — 94.8%, тобто дерево практично дістає ідеал. При 25° — уже 88.6%, при 45° — 88.5%. Стеля при цьому не змінюється взагалі: пряма під будь-яким кутом розділяє ті самі точки так само добре, бо повернулись і точки, і межа разом. Отже втрачені 6.1 відсоткового пункта — це не складність задачі, а невдалий вибір системи координат.

Практичний висновок. Якщо ти здогадуєшся, що важлива не сама величина, а співвідношення двох величин, — порахуй його й додай окремою колонкою. Одна ознака «витрати поділити на стаж» замінює деревові десяток сходинок, які воно інакше будувало б наосліп. Для лінійної моделі така робота не потрібна — вона й так уміє складати ознаки з вагами; для дерева це часто найдешевший спосіб різко підняти якість.
Зате масштаб не важить взагалі. Порівняння x ≤ t не змінюється, якщо ознаку помножити на 100 або виміряти в інших одиницях — поріг просто перерахується. Помножили витрати на тисячу, щоб рахувати в гривнях замість тисяч гривень, — дерево вийде буквально те саме, лише в порогах стоятиме 4730 замість 4.73. Те саме з будь-яким монотонним перетворенням, тобто таким, що не міняє порядок обʼєктів: логарифм, корінь, переведення в проценти. Тому деревам, на відміну від градієнтних методів і kNN, стандартизація ознак не потрібна взагалі. Це одна з причин, чому їх так люблять на «брудних» табличних даних.

ЧистотаЕнтропія: міра безладу

Тепер головне питання: як алгоритм обирає, де саме різати? Потрібна числова відповідь на питання «наскільки в цьому прямокутнику намішано класів». Набір, де всі обʼєкти одного класу, називають чистим; набір, де класи порівну, — максимально брудним.

Класична міра безладу прийшла з теорії інформації. Клод Шеннон 1948 року шукав, як виміряти кількість інформації в повідомленні, і отримав величину, яку назвав ентропією. У формулі стоїть логарифм, тож спершу розберімось із ним — без нього далі не буде зрозуміло нічого.

Що таке логарифм за основою 2. Це відповідь на питання «у який степінь треба піднести двійку, щоб отримати це число». Записують log₂8 і читають «логарифм вісім за основою два». Оскільки 2·2·2 = 8, відповідь дорівнює 3. Так само log₂1 = 0 (двійка в нульовому степені — це одиниця), log₂2 = 1, log₂16 = 4.

Побутовою мовою: логарифм за основою 2 — це кількість поділів навпіл. Скільки разів треба поділити 8 навпіл, щоб дійти до одиниці? Три рази: 8 → 4 → 2 → 1. Ось тобі log₂8 = 3. Це та сама гра у двадцять питань: кожне питання ділить світ навпіл, і логарифм каже, скільки таких питань потрібно.

Для чисел, менших за одиницю, логарифм відʼємний: щоб отримати одну восьму, двійку треба піднести в мінус третій степінь, тому log₂0.125 = −3. Це знадобиться за секунду. І остання дрібниця: логарифм не мусить бути цілим — log₂3 ≈ 1.585, бо трійка лежить між двійкою (log 1) і четвіркою (log 2).

Тепер сама формула:

H = − Σi pi · log2 pi

Словами, без жодного символу: ентропія — це середня кількість питань «так / ні», яку доведеться поставити, щоб дізнатись клас навмання взятого обʼєкта з набору.

Що означає кожен символ:

Навіщо вона тут: дереву треба одним числом сказати, наскільки в цьому вузлі намішано класів, — щоб потім порівняти «було» і «стало» після розрізу. Ентропія й дає це одне число.

чому саме логарифм, а не щось простіше

Шеннон шукав міру, яка має одну властивість: інформація двох незалежних питань мусить додаватись. Якщо одне питання відрізає половину варіантів, а друге — половину від решти, разом вони мають коштувати рівно два біти, а не «півтора» й не «чотири».

Але кількість варіантів при цьому не додається, а множиться: дві половинки від восьми — це 8 → 4 → 2, тобто ділення на 2 і ще раз на 2. Потрібна функція, яка перетворює множення на додавання. Такою функцією є рівно одна річ у математиці — логарифм: log₂(a·b) = log₂a + log₂b. Ось і вся причина. Логарифм тут не прикраса й не традиція, а єдиний спосіб, щоб біти складались як біти.

звідки взявся множник pi

Величина −log₂p — це «ціна» однієї конкретної відповіді: рідкісна подія (мале p) коштує багато бітів, часта — мало. Але нас цікавить не одна відповідь, а середня по всьому вузлу. Середнє рахують так: кожну ціну множать на те, як часто вона трапляється, і складають. Частота — це і є pi. Тому у формулі стоїть сума pi · (−log₂pi).

Для двох класів формула спрощується: якщо частка першого класу дорівнює p, то другого — рівно (1 − p), бо третього нема куди подітись. Отже вся ентропія залежить від одного числа:

H(p) = − p·log2p − (1−p)·log2(1−p)

Ентропія і Джині як функції складу

Тягни повзунок: змінюється частка класу «лишиться» у вибірці. Дивись на обидві криві.

ентропія, біт—
Джині—
помилка більшості—
Три властивості ентропії: вона дорівнює нулю тільки для чистого набору; вона максимальна, коли класи рівні; і будь-яке вирівнювання часток її збільшує. Саме ці три властивості й роблять її придатною мірою безладу.

Порахуймо руками

Візьмімо вузол із 40 клієнтів і проженімо три склади. Тобі знадобляться лише два значення логарифма: log₂1 = 0 і log₂0.5 = −1.

  1. Усі 40 лишились. Тоді p = 40 / 40 = 1 для класу «лишиться» і 0 для «піде». Доданок нульового класу пропускаємо (його частка нульова, і він нічого не додає), а перший дає −1 · log₂1 = −1 · 0 = 0. Ентропія 0 біт: невизначеності немає взагалі, питання ставити нема про що. Це готовий листок.
  2. 20 лишились, 20 пішли. Обидві частки дорівнюють 0.5. Рахуємо: −0.5·(−1) − 0.5·(−1) = 0.5 + 0.5 = 1. Ентропія 1 біт — рівно одне питання «так / ні» відділяє нас від відповіді, і це максимум для двох класів. Саме такий вузол алгоритм найбільше хоче розрізати.
  3. 30 лишились, 10 пішли. Частки 0.75 і 0.25. Тут потрібні log₂0.75 ≈ −0.415 і log₂0.25 = −2 (бо чверть — це два поділи навпіл). Рахуємо: −0.75·(−0.415) − 0.25·(−2) = 0.311 + 0.5 = 0.811. Ентропія 0.811 біт — уже менше за максимум, але далеко не нуль.

Помічаєш? Ентропія не питає, скільки обʼєктів у вузлі. Вона питає тільки, в якій пропорції вони поділені. Вузол із 4 обʼєктів «3 і 1» і вузол із 400 «300 і 100» мають ту саму ентропію 0.811 біт. Розмір вузла врахується окремо, у наступному розділі — і це буде важливо.

Для більш ніж двох класів усе те саме, лише доданків більше. Для трьох рівних класів максимум становить log₂3 ≈ 1.585, для восьми рівних — рівно 3 біти: щоб вгадати один із восьми варіантів, потрібно три питання «так / ні».

Вибір розрізуПриріст інформації

Ентропія міряє безлад в одному наборі. Але розріз створює два набори, і треба якось порівняти «було» з «стало». Тут є тонкість: після розрізу в нас дві ентропії, і просто додати їх не можна — вузол зі ста обʼєктів важить більше за вузол із трьох.

Розвʼязок — зважене середнє, де вага кожного нащадка дорівнює частці обʼєктів, які до нього потрапили. Різниця між ентропією до розрізу і зваженою ентропією після нього називається приростом інформації (information gain):

IG = Hбатько − ( NL/N · HL + NR/N · HR )

Словами: скільки бітів безладу зникло завдяки цьому питанню.

Символи: Hбатько — ентропія вузла до розрізу; N — скільки обʼєктів у ньому було; NL і HL — розмір і ентропія вузла, куди пішли ті, хто відповів «так» (індекс L від left, лівий нащадок); NR і HR — те саме для тих, хто відповів «ні» (right, правий нащадок). Дроби NL/N і NR/N — це частки обʼєктів, що пішли ліворуч і праворуч; вони завжди додаються до одиниці.

Навіщо: це та єдина оцінка, за якою алгоритм порівнює між собою всі можливі питання й обирає одне.

чому саме зважене середнє

Уяви розріз, який відрізає одну-єдину точку. Вона одна, отже її вузол ідеально чистий: H = 0. Якби ми брали просте середнє двох ентропій, такий розріз здався б чудовим — половина доданків обнулилась! Зважування ставить усе на місце: вузол з однієї точки має вагу 1/N і майже не впливає на результат.

чому IG ніколи не відʼємний

Зважена ентропія нащадків не може перевищити ентропію батька — це наслідок опуклості логарифма. У найгіршому випадку розріз нічого не змінює (обидва нащадки мають той самий склад, що й батько), і тоді IG = 0. Тому нульовий приріст — це сигнал «краще не різати».

скільки порогів треба перевірити

Приріст залежить не від точного значення порога, а лише від того, як він розділяє відсортовані обʼєкти. Тому кандидатів рівно на один менше, ніж різних значень ознаки: беруть середини між сусідніми значеннями. Для n обʼєктів і m ознак це m·(n−1) варіантів — на наших 200 клієнтах і двох ознаках виходить 398, — і всі вони перебираються повним перебором, без жодної хитрості. (Літеру m тут узято навмисне: p у цій лекції вже зайняте часткою класу.)

Порахуймо приріст руками — на справжньому розрізі

Візьмімо корінь нашого дерева: усі 200 навчальних клієнтів, з яких 103 лишились і 97 пішли. І перевірмо один конкретний розріз — «витрати ≤ 7.76 тис. грн». Усе, що потрібно, — чотири рядки арифметики.

крок 1 · ентропія батька

Частка класу «лишиться» дорівнює 103 / 200 = 0.515, класу «піде» — 0.485. Логарифми: log₂0.515 ≈ −0.957, log₂0.485 ≈ −1.044.

Hбатько = 0.515·0.957 + 0.485·1.044 = 0.493 + 0.506 = 0.999 біт

Майже рівно один біт — класи в корені поділені майже навпіл, безлад максимальний.

крок 2 · що дав розріз

Клієнтів із витратами до 7.76 виявилось 157: із них 63 лишились, 94 пішли. Решта 43 — у вузлі «ні»: 40 лишились, 3 пішли.

HL (157 обʼєктів, p = 63/157 = 0.401) = 0.972 біт
HR (43 обʼєкти, p = 40/43 = 0.930) = 0.365 біт

Вузол «ні» став майже чистим: у ньому майже самі ті, хто лишається. Вузол «так» майже не покращився — там усе ще намішано.

крок 3 · зважене середнє

Ваги — це частки обʼєктів: 157/200 = 0.785 і 43/200 = 0.215.

0.785 · 0.972 + 0.215 · 0.365 = 0.763 + 0.078 = 0.841 біт
крок 4 · приріст
IG = 0.999 − 0.841 = 0.158 біт

Тобто це питання прибрало приблизно шосту частину невизначеності. Звучить скромно — але саме це найкраще, що можна витиснути з одного питання на цих даних. Найкращий розріз за другою ознакою, стажем, дає лише 0.119 біт, тому коренем стане питання про витрати.

Візьми олівець і перевір крок 3: якщо замість ваг 0.785 і 0.215 узяти по половині, вийде (0.972 + 0.365) / 2 = 0.669, і «приріст» роздувся б до 0.331 — удвічі більший за справжній. Ось ціна незваженого середнього, про яку йшлося вище.

Наступний інтерактив показує цей перебір наживо. Угорі — розріз, який ти рухаєш повзунком, унизу — приріст інформації для всіх можливих порогів одразу. Алгоритм обере вершину чорної кривої:

Перебір усіх порогів

Нижній графік — три криві: ентропія вузла «так», вузла «ні» і приріст інформації. Ромб — оптимум.

H батька—
IG зараз—
H вузла «так»—
H вузла «ні»—
Спробуй: зсунь поріг у самий край — один вузол забирає майже всі точки, другий майже порожній, і приріст падає до нуля. Порівняй також дві ознаки: найкращий розріз за витратами дає 0.158 біт, найкращий за стажем — лише 0.119. Саме тому коренем стане питання про витрати.

АльтернативаКритерій Джині

Ентропія — не єдина міра безладу. На практиці частіше використовують індекс Джині, і за замовчуванням у scikit-learn стоїть саме він:

Gini = 1 − Σi pi2     для двох класів: 2p(1−p)

Символи ті самі, що в ентропії: pi — частка i-го класу, Σ — знак суми, а 2 означає «помножити саме на себе». Логарифмів тут немає взагалі — тільки множення й віднімання. Перевір на знайомому складі: якщо класи порівну, p = 0.5, то Gini = 1 − 0.25 − 0.25 = 0.5; якщо вузол чистий, p = 1, то Gini = 1 − 1 = 0; для складу «30 і 10» (p = 0.75) виходить 1 − 0.5625 − 0.0625 = 0.375.

У Джині є гарна ймовірнісна інтерпретація. Витягни з вузла випадковий обʼєкт, подивись на його клас, поверни назад. Витягни другий. Джині — це ймовірність, що класи двох витягнутих обʼєктів не збігуться. У чистому вузлі така подія неможлива, звідси нуль; при рівних класах вона трапляється в половині випадків, звідси 0.5.

Обидві криві на інтерактиві 3 мають однакову форму: нуль на краях, максимум у центрі, горб угору. Різниця в масштабі (ентропія доходить до 1, Джині до 0.5) і в тому, що ентропія трохи «гостріше» карає майже-чисті вузли. Практичні наслідки:

критерійформуламаксимумособливість
Ентропія−Σ p log₂ p1 бітпотребує логарифмів — трохи повільніша
Джині1 − Σ p²0.5тільки множення, за замовчуванням у sklearn
Помилка1 − max p0.5без вигину — погано розрізняє розрізи

Третій рядок пояснює, чому дерева не оптимізують безпосередньо точність. Подивись на сіру криву на інтерактиві 3: це два прямі відрізки, що сходяться гострим кутом посередині. Пряма ділянка означає, що на ній величина змінюється рівномірно, — а тоді розріз, який перекинув десять обʼєктів із одного вузла в інший, і розріз, який перекинув їх зовсім інакше, дадуть однакове число. Дві криві з вигином — Джині й ентропія — такі випадки розрізняють.

Показати це найлегше на цифрах. Уяви вузол із 800 клієнтів, у якому рівно 400 пішли й 400 лишились, і два різні розрізи. Перший ділить його на дві рівні половини, у кожній із яких перевага три до одного. Другий відрізає невелику групу, зате ідеально чисту:

розрізвузол «так»
піде / лишиться
вузол «ні»
піде / лишиться
помилкаДжиніентропія
батько400 / 400 разом0.5000.5001.000
А300 / 100 (400 шт.)100 / 300 (400 шт.)0.2500.3750.811
Б200 / 400 (600 шт.)200 / 0 (200 шт.)0.2500.3330.689

За помилкою більшості обидва розрізи однакові: 0.250 проти 0.250. Тобто міра «частка помилок» узагалі не бачить між ними різниці й обере той, що трапиться першим. А різниця величезна: розріз Б віддав нам двісті клієнтів, про яких усе відомо остаточно, — далі цю гілку можна не чіпати. І Джині, і ентропія це бачать: 0.333 проти 0.375 і 0.689 проти 0.811. Обидві криві з вигином віддають перевагу розрізу Б.

Ось за що дерева платять логарифмами й квадратами замість простого підрахунку помилок: за здатність відрізнити «стало трохи рівномірно краще» від «зʼявився шматок остаточної правди». Другого простий лічильник помилок не помічає.

Коли Джині й ентропія розходяться, а коли ні

Коротка відповідь: майже завжди вони обирають ту саму ознаку й дуже часто — різний поріг. Наші дані показують це буквально. Обидві міри в корені хочуть різати за витратами. Але:

розріз у кореніприріст за ентропієюприріст за Джині
витрати ≤ 7.760.158 ← найкращий0.094
витрати ≤ 4.730.1510.101 ← найкращий

Дві міри поставили ті самі два розрізи в протилежному порядку — і подивись, на скільки: за ентропією різниця 0.158 проти 0.151, тобто менш ніж 5%. Кандидати практично рівноцінні, і мікроскопічна різниця в мірі безладу вирішує все. Це та сама нестабільність, про яку йтиметься в розділі 11, тільки викликана не зміною даних, а зміною формули.

Наслідок видно на дереві: за Джині корінь — «витрати ≤ 4.73», за ентропією — «витрати ≤ 7.76», і далі дерева розходяться. На малій глибині це коштує помітно: дерево глибини 1 за Джині дає 75.1% на тесті, за ентропією — 65.8%. Але вже з глибини 5 обидва виходять на 84–85%, а розбіжність між ними падає з 30% площини до 6–8%. Наступний інтерактив дає проганяти це самому.

Що з цього робити на практиці. Бери gini, який стоїть у scikit-learn за замовчуванням, і не витрачай на цей вибір багато часу. Дивись на числа вище правильно: коли дерево ще замале й недонавчене (глибина 1 і 2), різниця величезна — 9.3 відсоткового пункта, — але це різниця між двома однаково поганими моделями. Щойно дерево дістає достатньо глибини, обидва критерії приходять до майже однакової якості. Тобто велика розбіжність між Джині й ентропією — це не привід вибирати критерій, а ознака того, що дерево ще не доросло. Глибина, мінімальний розмір листка й обрізання важать тут на порядок більше.

Ентропію варто спробувати, коли класи сильно незбалансовані: подивись на криві в інтерактиві 3 біля самого краю — рожева спадає до нуля помітно повільніше за бірюзову. Отже за ентропією вузол «майже чистий» усе ще коштує помітних бітів, і розріз, який дочищає рідкісний клас, має шанс виграти.
Не переплутай, яка міра де. Інтерактив 4 з попереднього розділу рахує ентропію, бо на ній зручно пояснювати біти. Усі інші інтерактиви цієї лекції будують дерева за Джині — так, як це робить scikit-learn за замовчуванням. Тому поріг кореня 7.76 на інтерактиві 4 і 4.73 на інтерактиві 6 — не помилка й не різні дані, а рівно та розбіжність критеріїв, про яку йшлося вище.

Джині проти ентропії на тих самих даних

Два дерева тієї самої глибини, навчені на однаковій вибірці різними критеріями.

test · Джині—
test · ентропія—
листків G / E—
розбіжність—
Що читати: «розбіжність» — частка площини, де два дерева дають різні відповіді. На малій глибині критерії можуть зачепитись за різні майже-рівноцінні розрізи й розійтись сильно; з глибиною вони сходяться до схожої межі.

АлгоритмЯк дерево навчається крок за кроком

Тепер усі складники є, і можна зібрати алгоритм навчання. Дві сімʼї алгоритмів зʼявились майже одночасно й незалежно одна від одної. ID3 Росса Квінлана (1986) увів приріст інформації як критерій вибору розрізу — і саме звідси в темі взялась ентропія. CART команди Лео Бреймана (1984) робить те саме, але з двома відмінностями: розрізи завжди двійкові, а безлад міряють Джині.

Це важливо не як історична довідка. DecisionTreeClassifier зі scikit-learn — оптимізований CART, а не ID3, тому в цій лекції ми описуємо саме двійкові розрізи «ознака ≤ поріг».

алгоритмрікрозрізиміра безладуобрізання
ID3 (Квінлан)1986по одній гілці на кожне значення ознакиприріст інформаціїнемає
C4.5 (Квінлан)1993двійкові для чисел, багатогілкові для категорійgain ratioє
CART (Брейман та ін.)1984завжди двійковіДжині (регресія: дисперсія)cost-complexity

Різниця між ID3 і CART важливіша, ніж здається. ID3 умів працювати тільки з категоріальними ознаками — на кшталт «місто клієнта» — і на кожне значення робив окрему гілку. Ознака «місто» з тридцятьма значеннями розколювала вузол одразу на тридцять частин, у кожній із яких лишалась жменька обʼєктів. Такі гілки виглядають чистими просто тому, що вони крихітні, і ID3 систематично закохувався в ознаки з великою кількістю значень. C4.5 полагодив це нормуванням (gain ratio), а CART — тим, що взагалі не робить більш ніж двох гілок. Ту саму хворобу ми ще зустрінемо наприкінці лекції, коли говоритимемо про важливість ознак.

Сам порядок дій у всіх трьох однаковий:

  1. Почни з кореня. У корені лежить уся навчальна вибірка. Порахуй її ентропію (або Джині) — це відправна точка.
  2. Перебери кандидатів. Для кожної ознаки відсортуй обʼєкти й розглянь усі пороги між сусідніми значеннями. Для кожного порога порахуй зважену ентропію двох нащадків і приріст інформації.
  3. Візьми найкращий розріз. Той, у якого приріст максимальний. Створи вузол рішення з цією ознакою й цим порогом. Ніяких «а що як інший розріз краще спрацює через два кроки» — вибір робиться тут і зараз.
  4. Розділи дані на дві частини й запусти ту саму процедуру окремо для кожної. Це рекурсія: кожен нащадок стає новим коренем для своєї підзадачі.
  5. Зупинись і зроби листок, коли спрацював один із критеріїв зупинки. У листку записується мітка більшості (для класифікації) або середнє значення (для регресії).

Простежмо два перші кроки на наших даних, щоб рекурсія перестала бути словом.

  1. Корінь. 200 клієнтів, склад 97 / 103, Джині 0.500. Алгоритм перебирає 199 порогів за стажем і 199 за витратами — разом 398 варіантів — і перемагає «витрати ≤ 4.73» з приростом 0.101.
  2. Ліва гілка («так», витрати не більші за 4.73). Сюди дійшло 96 клієнтів, з них пішли 69. Тепер це окрема, менша задача, і алгоритм робить із нею рівно те саме: перебирає всі пороги всередині цих 96 обʼєктів. Перемагає «стаж ≤ 17.10». Зверни увагу: ознака інша, ніж у корені, і поріг такий, якого в корені не було в переможцях, — бо склад даних тут інший.
  3. Права гілка («ні», витрати більші за 4.73). Тут 104 клієнти, з них лишились 76. Незалежно від того, що сталось у лівій гілці, алгоритм перебирає пороги тут і бере «стаж ≤ 9.87».
  4. Далі кожна з чотирьох утворених груп ділиться так само, і так доки не спрацює гальмо.

Це і є вся рекурсія: одна й та сама процедура, застосована до дедалі менших шматків даних. Ніякої «глобальної оптимізації» немає — є 200 обʼєктів, потім 96 і 104, потім 64, 32, 35, 69, і в кожному вузлі своя маленька незалежна задача.

Скільки це коштує. У вузлі з n обʼєктами і p ознаками треба відсортувати обʼєкти за кожною ознакою (n·log n дій) і пройти список один раз, оновлюючи лічильники класів. Разом на рівень виходить приблизно p·n·log n дій, а рівнів зазвичай десяток. Тому дерево на таблиці в сотню тисяч рядків навчається за секунди — це одна з причин, чому ансамблі з сотень дерев узагалі можливі.
Алгоритм жадібний. «Жадібний» означає буквально: на кожному кроці він хапає те, що найкраще просто зараз, і ніколи не повертається переглянути своє рішення. Побудувати доведено оптимальне дерево — NP-складна задача, тобто така, де надійного способу, крім перебору всіх варіантів, не знайдено; для 398 кандидатів на кожному з десяти рівнів це неосяжно. Тому жадібність тут не лінощі, а необхідність.

Ціна така: існують задачі, де перший розріз із нульовим приростом відкрив би шлях до ідеального дерева, але алгоритм його не зробить. Класичний приклад — «виключне АБО»: уяви, що клієнт лишається, коли рівно одна з двох умов виконана, а коли обидві або жодна — іде. На площині це шахівниця два на два. Будь-який одиничний розріз ділить її на дві половини, у кожній із яких класи знову порівну, — приріст рівно нуль, і жадібний критерій каже «різати нема сенсу». Хоча два розрізи поспіль розвʼязали б задачу ідеально.

СтруктураЯк виглядає готове дерево

Ту саму модель, яку ми досі бачили як плитки на площині, можна намалювати як схему. Це не інша модель — це той самий обʼєкт з іншого боку. Одна плитка на площині — це один листок на схемі; одна лінія розрізу на площині — це один вузол рішення на схемі. Корінь угорі, під ним два нащадки, під ними їхні нащадки. Кожен вузол підписаний питанням, а колірна смужка показує склад класів у ньому. Дивись, як дерево росте, коли ти дозволяєш йому ще один рівень:

Дерево як схема

Смужка під питанням — склад вузла. Число під нею — скільки навчальних обʼєктів сюди дійшло.

вузлів рішення—
листків—
чистих листків—
H кореня—
Прочитай модель уголос: спустись від кореня вліво-вправо за питаннями — і отримаєш звичайне правило «якщо витрати > 4.7, стаж > 9.9 і стаж ≤ 22.6, то клієнт лишиться» (при глибині 3 в цьому листку 58 обʼєктів). Жодна інша сімʼя моделей не перекладається людською мовою так дослівно.

Те саме дерево словами

Схема гарна, але її треба вміти прочитати. Ось те саме дерево глибини 3, виписане повністю. Відступ означає рівень; «так» веде ліворуч, «ні» — праворуч. Праворуч — n, скільки навчальних клієнтів дійшло до вузла, і склад «піде / лишиться».

витрати ≤ 4.73?                    n=200    97 / 103
├─ так → стаж ≤ 17.10?             n= 96    69 /  27
│  ├─ так → стаж ≤ 8.56?           n= 64    55 /   9
│  │  ├─ так → листок «піде»       n= 26    25 /   1
│  │  └─ ні  → листок «піде»       n= 38    30 /   8
│  └─ ні  → витрати ≤ 2.21?        n= 32    14 /  18
│     ├─ так → листок «піде»       n= 15    14 /   1
│     └─ ні  → листок «лишиться»   n= 17     0 /  17
└─ ні  → стаж ≤ 9.87?              n=104    28 /  76
   ├─ так → витрати ≤ 7.85?        n= 35    21 /  14
   │  ├─ так → листок «піде»       n= 20    20 /   0
   │  └─ ні  → листок «лишиться»   n= 15     1 /  14
   └─ ні  → стаж ≤ 22.60?          n= 69     7 /  62
      ├─ так → листок «лишиться»   n= 58     4 /  54
      └─ ні  → листок «лишиться»   n= 11     3 /   8

Сім вузлів рішення, вісім листків — і це вся модель. Ніяких ваг, ніяких матриць: сім питань і вісім пар чисел.

Чотири речі, які варто помітити в цьому дереві

Як прочитати прогноз для конкретного клієнта

Прийшов клієнт: стаж 20 місяців, витрати 6.4 тис. грн на місяць. Спускаємось:

  1. Витрати 6.4 більші за 4.73 → відповідь «ні», ідемо праворуч, у вузол зі 104 клієнтів.
  2. Стаж 20 більший за 9.87 → знову «ні», праворуч, у вузол із 69 клієнтів.
  3. Стаж 20 не більший за 22.60 → «так», ліворуч, у листок «58 обʼєктів: 4 піде / 54 лишиться».
  4. Відповідь: лишиться, з оцінкою ймовірності 54 / 58 = 0.931.

Три порівняння чисел — і готово. Це і є той самий шлях, який на площині означає прямокутник «витрати від 4.73 і вище, стаж від 9.87 до 22.60». Правило, яке отримали, можна записати одним реченням і показати кому завгодно: «якщо клієнт витрачає понад 4.73 тисячі на місяць і обслуговується від десяти до двадцяти двох місяців — він лишиться, і ми в цьому впевнені на 93%». Жодна інша сімʼя моделей не перекладається людською мовою так дослівно.

ГальмаКритерії зупинки

Якщо алгоритму не заважати, він працюватиме, доки кожен листок не стане ідеально чистим. Для будь-яких даних без повторюваних обʼєктів це завжди можливо: у найгіршому випадку дерево виділить кожному обʼєкту власний листок. Навчальна точність стане рівно 100%, а модель — марною.

Це не риторична фігура, а заміряний факт на наших даних. Ось що коштує відсутність гальм:

дереволистківточність trainточність testрозрив
без гальм37100.0%81.0%19.0 в. п.
глибина 3891.0%86.8%4.2 в. п.
min_samples_leaf = 161090.0%87.5%2.5 в. п.

Тобто дерево, яке вивчило навчальні дані напамʼять, працює на нових клієнтах на 6.5 відсоткового пункта гірше за дерево з десятьма листками замість тридцяти семи. Гальма — не косметика, вони і є половина роботи з деревом.

Пʼять гальм і що кожне робить

параметрщо обмежуєяк діє
max_depthкількість питань поспільнайгрубіше й найзрозуміліше гальмо
min_samples_leafрозмір листказабороняє листки з двох-трьох обʼєктів
min_samples_splitрозмір вузла для розрізуне дає різати й без того малі вузли
max_leaf_nodesзагальну кількість листківріже тільки найприбутковіші вузли
min_impurity_decreaseмінімальний приріствідсікає розрізи «ні про що»
За замовчуванням гальм немає жодного. У DecisionTreeClassifier зі scikit-learn стоїть max_depth=None, min_samples_leaf=1, min_samples_split=2, max_leaf_nodes=None, min_impurity_decrease=0.0. Тобто виклик DecisionTreeClassifier() без аргументів дає рівно перший рядок таблиці вище: дерево, що доросло до 100% на навчальних даних. Це не помилка бібліотеки — це чесна відмова вгадувати за тебе, скільки складності витримають твої дані. Але це означає, що дерево з коробки майже завжди перенавчене.

Яке гальмо тиснути першим

Гальма не рівноцінні, і порядок такий:

Правильне значення жодного з них не вгадується з голови: воно залежить від того, скільки в тебе даних і скільки в них шуму. Його добирають перебором із крос-валідацією — так само, як будь-який інший гіперпараметр (тема 20). На наших 200 клієнтах перебір min_samples_leaf від 1 до 40 дав максимум при 16 — це 8% вибірки; на іншому наборі оптимум буде іншим.

Природні зупинки, які працюють завжди

параметрщо обмежуєяк діє
max_depthкількість питань поспільнайгрубіше й найзрозуміліше гальмо
min_samples_leafрозмір листказабороняє листки з двох-трьох обʼєктів
min_samples_splitрозмір вузла для розрізуне дає різати й без того малі вузли
max_leaf_nodesзагальну кількість листківріже тільки найприбутковіші вузли
min_impurity_decreaseмінімальний приріствідсікає розрізи «ні про що»

Крім штучних обмежень, є дві зупинки, які спрацьовують самі й яких не можна вимкнути:

Ці дві зупинки — саме та причина, чому дерево без гальм дає 100% на навчальних даних майже завжди, а не завжди: якщо в таблиці є два однакові рядки з різними мітками, 100% недосяжні навіть теоретично.

ПасткаЧому глибокі дерева перенавчаються

Розберімо механіку перенавчання буквально по кроках. Нехай у нашому наборі клієнт із дуже великими витратами все одно пішов — просто через обставини, які в даних не записані. Для дерева це не випадковість, а факт, який треба пояснити. Воно робить розріз, потім ще один, і зрештою будує навколо цього клієнта крихітний прямокутник, у якому лежить лише він.

Тепер у цьому прямокутнику модель прогнозує «піде» з упевненістю 100%. Будь-який новий клієнт, що випадково потрапить у цю зону, отримає впевнений і, найімовірніше, помилковий прогноз. Дерево вивчило не закономірність, а шум.

Чому 100% на навчальних даних — не досягнення

Тут потрібна одна річ, без якої весь розділ висить у повітрі: у наших даних є стеля, і вона не дорівнює 100%. Клієнтів згенеровано за чітким правилом «сходинки» — воно й намальоване пунктиром на кожній фігурі, — але приблизно кожну десяту мітку перевернуто навмисно, щоб імітувати обставини, яких у таблиці немає: хтось переїхав, хтось посварився з менеджером. Це і є шум.

Порахуймо стелю. Якби ми знали справжнє правило точно й застосували його до 800 нових клієнтів, ми б угадали 89.6% — решту зіпсував перевернутий шум. Це найкраще, чого взагалі може досягти будь-яка модель на цих даних. Тепер порівняй:

модельточність trainточність testдо стелі 89.6%
справжнє правило89.5%89.6%—
дерево глибини 391.0%86.8%−2.8 в. п.
дерево без обмежень100.0%81.0%−8.6 в. п.

Подивись на перший рядок уважно: саме правило, за яким дані створювались, дає на навчальній вибірці лише 89.5%. А дерево без обмежень дає 100%. Отже дерево описало навчальні дані краще, ніж істина, — і це вже не перемога, а діагноз. Єдиний спосіб перевершити істину на навчальних даних — вивчити напамʼять ті самі перевернуті мітки, які істиною не є.

Ось чому «100% на train» само по собі не означає нічого, і чому дивитись треба на розрив між train і test. У правильного правила розрив дорівнює −0.1 відсоткового пункта, у дерева глибини 3 — 4.2, у необмеженого — 19.0.

На кривих нижче видно два дуже різні сюжети. Навчальна точність росте монотонно й доходить до 100% — інакше й бути не може, бо глибше дерево завжди може дозаучити те, що не вмістилось. Тестова точність спочатку росте разом із нею, потім розвертається:

Глибина проти узагальнення

Рожева крива — точність на навчальних даних, бірюзова — на 800 нових клієнтах, яких модель не бачила.

train—
test—
розрив—
листків—
Головна ознака перенавчання — не низька тестова точність сама по собі, а розрив між train і test. Якщо на навчальних даних 100%, а на нових 81% — модель вивчила майже все, крім того, що було потрібно.

ЛікиОбрізання: до і після

Є два способи не дати дереву розростись, і вони працюють у різні моменти.

Попереднє обрізання (pre-pruning)

Це те, що ми вже бачили: обмеження, які зупиняють ріст під час навчання — max_depth, min_samples_leaf і компанія. Дешево і просто. Слабке місце — короткозорість: алгоритм зупиняється, побачивши слабкий розріз, і не дізнається, що одразу за ним був сильний. Це та сама проблема жадібності, тільки з іншого боку.

Мінімальний розмір листка

Глибина не обмежена. Єдине гальмо — заборона листків, менших за поріг.

train—
test—
листків—
найкраща test—
Гальмо працює вибірково: при значенні 1 межа всіяна крихітними острівцями навколо окремих точок. Зі зростанням порога зникають спершу вони — бо тримаються на одному-двох обʼєктах, — а великі прямокутники, під якими стоять десятки клієнтів, лишаються. Ось чому min_samples_leaf зазвичай корисніший за max_depth: він ріже там, де даних мало, і не заважає там, де їх багато.

Наступне обрізання (post-pruning)

Другий підхід чесніший: спочатку виростити дерево повністю, а потім зрізати гілки, які не виправдовують свого існування. У scikit-learn це cost-complexity pruning, він же алгоритм слабкої ланки. Кожному піддереву приписують «вартість»:

Rα(T) = R(T) + α · |листків T|

Словами: вартість дерева — це його помилка плюс орендна плата за кожен листок.

Символи: T — дерево (або будь-яке його піддерево); R(T) — частка помилок цього дерева на навчальних даних, число від 0 до 1; |листків T| — скільки в ньому листків; α (грецька мала «альфа») — ціна одного листка, яку призначаємо ми. Rα(T) — підсумкова вартість, яку алгоритм мінімізує.

Порахуймо на нашому дереві. Є два кандидати: повністю вирощене дерево (37 листків, 0 помилок із 200, тобто R = 0.000) і дерево глибини 3 (8 листків, 18 помилок, R = 0.090). Питання: за якої ціни листка більше дерево перестає окупатись?

вартість кожного
Rα(велике) = 0.000 + α · 37 = 37α
Rα(мале)   = 0.090 + α · 8  = 0.090 + 8α
де вони зрівнюються

Прирівнюємо й розвʼязуємо: 37α = 0.090 + 8α, отже 29α = 0.090, отже

α = 0.090 / 29 ≈ 0.0031
що це означає

Поки листок коштує менш ніж 0.0031, вигідніше велике дерево: кожен зайвий листок окупається зменшенням помилки. Щойно ціна переступає 0.0031 — вигіднішим стає мале. Перевір підстановкою: при α = 0.01 велике дерево коштує 0.37, а мале — 0.17, тобто більш ніж удвічі дешевше.

При α = 0 вигідне найбільше дерево завжди — воно ж має нуль помилок. Зі зростанням α листки один за одним стають нерентабельними, і алгоритм згортає найслабші піддерева у листки. Виходить не одне дерево, а ціла послідовність вкладених дерев від найбільшого до пенька; правильне α обирають крос-валідацією.

Чому це чесніше за попереднє обрізання: рішення про кожну гілку ухвалюється, коли вже видно, що під нею виросло. Попереднє обрізання зупиняє алгоритм наосліп, до того як стало відомо, чи був за слабким розрізом сильний.

Практична порада. У sklearn потрібні значення ccp_alpha отримують викликом tree.cost_complexity_pruning_path(X, y) — він повертає список усіх α, на яких дерево змінюється. Далі звичайний перебір по цьому списку з крос-валідацією. Це на порядок надійніше, ніж вгадувати max_depth навмання.

Слабке місцеНестабільність

А тепер найважливіша вада дерев, і саме вона за одну лекцію приведе нас до випадкового лісу.

Згадай, як обирається корінь: перебір усіх порогів і вибір максимуму приросту. Часто два чи три різні розрізи мають майже однаковий приріст. Наскільки «майже» — ми вже бачили на власні очі в розділі 5: у корені наших даних розріз «витрати ≤ 7.76» дає приріст 0.158, а «витрати ≤ 4.73» — 0.151. Різниця менш ніж 5%, тобто в межах того, що змінює одна жменька клієнтів. Але алгоритм детермінований: він бере максимум і не дивиться, наскільки той відірвався від другого місця. Переможець забирає все, і різниця в третьому знаку перетворюється на два зовсім різні дерева.

Тепер прибери з вибірки кілька випадкових обʼєктів або додай трохи шуму. Порядок кандидатів може помінятись: тепер виграє той, що був другим. Корінь інший — і вся структура під ним будується заново, бо кожен наступний розріз залежить від попереднього. Мала зміна на вході дає велику зміну на виході.

Важливо зрозуміти, чому це саме каскад, а не локальна дрібниця. Змінився корінь — змінилось, які саме 96 і 104 клієнти потрапили ліворуч і праворуч. А розріз у лівій гілці шукається тільки серед тих обʼєктів, які туди дійшли. Інший набір обʼєктів — інші кандидати, інший переможець, інші два вузли під ним. Помилка не гаситься з глибиною, а множиться: кожен рівень успадковує чужий поділ і додає до нього свій.

Ось що показує заміряний прогін. Те саме дерево (глибина 4, мінімальний листок 4) навчено вісім разів на випадкових підвибірках тих самих 200 клієнтів. Підвибірку беруть із поверненням: 200 разів витягують випадкового клієнта й щоразу повертають його назад, тож дехто потрапляє двічі-тричі, а дехто не потрапляє зовсім — у наших прогонах щоразу лишалось близько 125 різних клієнтів зі 200. Дані ті самі, змінюється тільки те, кому пощастило потрапити:

прогінпитання в коренілистківточність test
вихіднийвитрати ≤ 4.731486.8%
1витрати ≤ 7.081279.8%
2витрати ≤ 5.451382.4%
3витрати ≤ 5.431382.1%
4стаж ≤ 9.911376.8%
5витрати ≤ 4.621285.1%
6стаж ≤ 15.321275.4%
7витрати ≤ 5.431381.0%
8стаж ≤ 11.021183.1%

Три прогони з восьми змінили саму ознаку в корені — не поріг, а питання. Тестова точність гуляє від 75.4% до 85.1%, тобто на 9.7 відсоткового пункта. І це при тому, що дані ті самі, алгоритм той самий і жодного випадкового числа всередині алгоритму немає: змінилось лише те, які саме клієнти потрапили у вибірку.

Порівняй із лінійною регресією: там викидання кількох точок трохи посуне коефіцієнти, але форма моделі — пряма — лишиться прямою, і читати її треба буде так само. Дерево ж міняє не числа всередині відомої форми, а саму структуру: інші питання в іншому порядку. Саме тому одне дерево не можна показувати замовникові зі словами «ось які ознаки насправді важливі»: на іншій половині тих самих даних вийшов би інший список.

Те саме завдання, інша підвибірка

Кожне натискання — нова випадкова підвибірка тих самих клієнтів і навчання з нуля.

корінь—
листків—
test—
інша відповідь—
«Інша відповідь» — частка площини, де нове дерево класифікує інакше, ніж попереднє. За перші вісім прогонів вона трималась між 7.5% і 16.9%, а тестова точність гуляла від 75.4% до 85.1% — тобто жодне з дерев не є «правильним», вони просто по-різному вгадують.

Мовою зміщення й дисперсії: у глибокого дерева мале зміщення (воно здатне описати майже будь-яку залежність) і велика дисперсія (результат сильно залежить від конкретної вибірки). Обрізання зменшує дисперсію ціною зміщення, але повністю проблему не знімає.

Куди це веде. Якщо кожне окреме дерево гуляє навколо правильної відповіді, а гуляє воно в різні боки, то середнє з багатьох дерев має гуляти менше — помилки різних знаків частково погасять одна одну. Найдешевший спосіб отримати «багато дерев» з однієї вибірки ми вже застосували в таблиці вище: витягувати підвибірки з поверненням. Це і є беггінг, а дерева на таких підвибірках — випадковий ліс: тема 24.

І зверни увагу на парадокс, який робить ансамблі можливими: нестабільність із вади перетворюється на ресурс. Стабільна модель на всіх підвибірках дає майже те саме, і усереднювати нема чого. Дерево ж кожного разу помиляється по-новому — саме тому з нього виходить хороший будівельний матеріал.

БалансЩо дерево вміє краще за всіх

Попри всі вади дерева лишаються робочим інструментом, і не тільки як цеглинка для ансамблів. Ось за що їх цінують:

А ось за що не варто братися деревом:

Про важливість ознак. Дерева вміють показувати, які ознаки дали найбільший сумарний приріст: для кожної ознаки складають прирости всіх розрізів, де вона брала участь, зважені на розмір вузла. У scikit-learn це поле feature_importances_.

Читати ці числа треба обережно. Оцінка систематично завищує ознаки з великою кількістю різних значень: у неперервної ознаки на 200 обʼєктах є 199 кандидатів на поріг, а в ознаки «так / ні» — рівно один. Що більше спроб, то вищий шанс, що якийсь поріг випадково ляже вдало на шум. Тому ідентифікатор клієнта, який не означає взагалі нічого, може отримати помітну «важливість» просто тому, що він унікальний у кожного. Це та сама хвороба, через яку ID3 закохувався в багатозначні категорії (розділ 6). Детально — у темі 24.

ПідсумокЩо варто винести

Дерево рішень — це послідовність питань «ознака ≤ поріг», яка розкладає простір на прямокутники. Питання обираються жадібно: на кожному кроці той розріз, що найбільше зменшує безлад. Безлад міряють ентропією або Джині; різниця між ними на практиці невелика, а от різниця між обмеженим і необмеженим ростом — величезна.

Ланцюжок, який варто вміти переказати без підказки: ентропія міряє безлад в одному вузлі → приріст інформації порівнює безлад до й після розрізу → жадібний перебір бере розріз із найбільшим приростом → рекурсія повторює це в кожному нащадку → гальма кажуть, коли спинитись. Усе інше в темі — наслідки цих пʼяти кроків.

Пʼять речей, які легко забути й дорого відновлювати: