Підготовка до співбесіди з класичного машинного навчання
Запитання для співбесіди інженера з класичного машинного навчання
15 відібраних запитань для співбесіди з класичного машинного навчання, згрупованих за рівнем досвіду. Використовуйте їх для повторення основ, практичних компромісів та міркувань щодо продакшену на старшому рівні.
1Яка різниця між параметром моделі та гіперпараметром у навчанні з учителем?
У машинному навчанні з учителем параметри моделі — це внутрішні змінні, які вивчаються безпосередньо з навчальних даних за допомогою алгоритму оптимізації (наприклад, градієнтного спуску або нормальних рівнянь). Приклади включають регресійні ваги та зміщення в лінійних моделях або пороги розбиття в деревах рішень.
Натомість, гіперпараметри — це зовнішні налаштування конфігурації, які задаються до початку навчання і керують процесом навчання, потужністю моделі або архітектурою. Їх не можна вивчити безпосередньо за допомогою стандартної мінімізації функції втрат під час навчання, оскільки оптимізатор тривіально перенавчиться (наприклад, встановивши глибину дерева в нескінченність). Приклади включають швидкість навчання, силу регуляризації (лямбда/C), кількість дерев у лісі та максимальну глибину дерева. Гіперпараметри налаштовуються за допомогою валідаційних даних або крос-валідації.
from sklearn.linear_model import Ridge
import numpy as np
X = np.array([[1.0], [2.0], [3.0]])
y = np.array([2.0, 4.0, 6.0])
# Hyperparameter: alpha (regularization strength set beforehand)
model = Ridge(alpha=1.0)
# Fitting optimizes internal parameters on training data
model.fit(X, y)
# Learned parameters
print(f"Weight (Parameter): {model.coef_[0]:.4f}")
print(f"Intercept (Parameter): {model.intercept_:.4f}")
2Які припущення робить лінійна регресія за методом найменших квадратів (МНК), і як діагностика залишків виявить порушення цих припущень?
Лінійна регресія за методом найменших квадратів (МНК) покладається на кілька основних припущень:
1. **Лінійність**: Зв'язок між предикторами та результатом є лінійним за параметрами.
2. **Незалежність помилок**: Спостереження та залишкові помилки взаємно незалежні (відсутність автокореляції).
3. **Гомоскедастичність**: Члени похибки мають постійну дисперсію для всіх рівнів предикторів.
4. **Нормальність залишків**: Члени похибки розподілені нормально (необхідно для дійсних довірчих інтервалів та перевірок гіпотез).
5. **Відсутність мультиколінеарності**: Предиктори не є лінійно залежними (матриця плану має повний стовпцевий ранг).
Діагностика залишків виявляє порушення таким чином:
* **Графік «Залишки проти підігнаних значень»**: Викривлення або невипадкові закономірності виявляють нелінійність; лійкоподібна або віялоподібна форма виявляє гетероскедастичність (непостійну дисперсію).
* **Q-Q графік нормального розподілу**: Систематичне відхилення від прямої діагональної лінії (наприклад, S-подібні криві або важкі хвости) виявляє ненормальність.
* **Графік «Залишки проти порядку/часу»**: Систематичні тренди або циклічні закономірності виявляють автокорельовані помилки.
* **Графік важеля / відстані Кука**: Ідентифікує викиди з високим важелем або впливові точки, які непропорційно зміщують підігнану модель.
import numpy as np
import statsmodels.api as sm
np.random.seed(42)
X = np.linspace(1, 10, 50)
# Quadratic underlying pattern creates a linearity violation
y = 2 * X + 0.5 * (X ** 2) + np.random.normal(0, 2, 50)
X_with_const = sm.add_constant(X)
model = sm.OLS(y, X_with_const).fit()
residuals = model.resid
print(f"Mean Residual: {np.mean(residuals):.4f}")
print(f"Curvature in residuals indicates model misspecification.")
3Як логістична регресія моделює бінарну класифікацію, і яка роль сигмоїдної функції?
Логістична регресія моделює бінарну класифікацію шляхом оцінки апостеріорної ймовірності класу $P(Y=1|X)$. Щоб забезпечити обмеження прогнозованих ймовірностей у діапазоні $(0, 1)$, логістична регресія моделює логарифм шансів (логіт) позитивного класу як лінійну функцію вхідних даних: $\ln\left(\frac{p}{1-p}\right) = w^T x + b$. Сигмоїдна (логістична) функція, $\sigma(z) = \frac{1}{1 + e^{-z}}$, слугує як функція зв'язку, яка монотонно відображає будь-яку дійсну лінійну оцінку $z = w^T x + b \in (-\infty, +\infty)$ у дійсну ймовірність $p \in (0, 1)$. Рішення щодо дискретних класів приймаються шляхом застосування порогу прийняття рішень $\tau$ (зазвичай 0.5): $\hat{y} = 1$, якщо $P(Y=1|X) \ge \tau$, інакше $0$. Оскільки $\sigma(z) = 0.5$ виникає саме тоді, коли $z = 0$, межа прийняття рішень у просторі ознак є лінійною гіперплощиною $w^T x + b = 0$, що робить стандартну логістичну регресію лінійним класифікатором.
import numpy as np
def sigmoid(z):
return 1 / (1 + np.exp(-z))
w = np.array([1.5, -2.0])
b = 0.5
x = np.array([2.0, 1.0])
z = np.dot(w, x) + b
prob = sigmoid(z)
threshold = 0.5
pred = int(prob >= threshold)
print(f"Log-odds (z): {z:.2f}")
print(f"Probability: {prob:.4f}")
print(f"Class Prediction: {pred}")
4Що таке L2-регуляризація, і як гребенева регресія (Ridge regression) змінює цільову функцію та оцінки коефіцієнтів?
L2-регуляризація (гребенева регресія) додає штраф, пропорційний сумі квадратів ваг, до функції втрат методу найменших квадратів (МНК):
$$\min_w \|y - Xw\|_2^2 + \lambda \|w\|_2^2$$
Аналітично, гребенева регресія модифікує нормальні рівняння, додаючи $\lambda I$ до матриці Грама перед оберненням:
$$w_{\text{ridge}} = (X^T X + \lambda I)^{-1} X^T y$$
Ключові впливи на цільову функцію та оцінки коефіцієнтів:
1. **Стиснення**: Коефіцієнти стискаються до нуля пропорційно дисперсії ознак та кореляції, зменшуючи складність моделі без примусового зведення їх до точного нуля.
2. **Мультиколінеарність та оборотність**: Коли ознаки колінеарні або $p > N$, $X^T X$ є виродженою або погано обумовленою. Додавання $\lambda I$ забезпечує, що $(X^T X + \lambda I)$ є строго додатно визначеною та оборотною, стабілізуючи оцінки параметрів.
3. **Компроміс між зміщенням та дисперсією**: Збільшення $\lambda$ вводить навмисне зміщення в оцінки коефіцієнтів, водночас значно зменшуючи дисперсію, що призводить до меншої очікуваної помилки узагальнення на небачених даних.
4. **Вимога масштабування ознак**: Оскільки штраф розглядає всі ваги однаково, ознаки з більшими масштабами будуть регуляризовані непропорційно. Ознаки повинні бути стандартизовані (нульове середнє, одинична дисперсія) до підгонки моделі.
import numpy as np
def ridge_regression(X, y, alpha):
X_std = (X - np.mean(X, axis=0)) / np.std(X, axis=0)
n_features = X_std.shape[1]
I = np.eye(n_features)
beta = np.linalg.inv(X_std.T @ X_std + alpha * I) @ X_std.T @ y
return beta
X = np.array([[1.0, 2.0], [2.0, 4.1], [3.0, 5.9], [4.0, 8.2]])
y = np.array([2.1, 4.0, 6.2, 8.1])
weights = ridge_regression(X, y, alpha=1.0)
print('Ridge Weights:', weights)
5Як дерево рішень (decision tree) рекурсивно розбиває простір ознак (feature space), і які критерії використовуються для вибору розбиття класифікації?
Дерево рішень розбиває простір ознак за допомогою жадібного алгоритму (greedy algorithm) типу «зверху вниз», який називається **рекурсивним бінарним розбиттям (recursive binary partitioning)**. Починаючи з кореневого вузла (root node) з усіма навчальними даними, алгоритм шукає серед усіх ознак і можливих порогових значень, щоб знайти єдине розбиття, вирівняне по осях ($X_j \le t$), яке максимізує зменшення неоднорідності (impurity). Набір даних розбивається на два дочірні вузли (child nodes), і ця процедура застосовується рекурсивно до кожного дочірнього вузла, доки не буде досягнуто критерію зупинки (stopping criterion) (наприклад, максимальна глибина, мінімальна кількість зразків на лист або чисті вузли). Оскільки розбиття оцінюють одну ознаку за раз відносно порогу, отримані межі рішень є ортогональними гіперплощинами (прямокутні області, вирівняні по осях, у просторі ознак).
Для оцінки та вибору найкращого розбиття в деревах класифікації використовуються два основні критерії неоднорідності:
1. **Неоднорідність Джині (Gini Impurity) (використовується в CART)**: Вимірює ймовірність того, що випадково обраний зразок буде неправильно класифікований, якщо його випадково маркувати відповідно до розподілу класів вузла. Для $K$ класів з пропорціями $p_k$: $$I_G = 1 - \sum_{k=1}^K p_k^2$$
2. **Ентропія (Entropy) та Приріст інформації (Information Gain) (використовуються в ID3, C4.5)**: Ентропія вимірює невизначеність у вузлі: $H = -\sum_{k=1}^K p_k \log_2(p_k)$. Розбиття вибирається для максимізації **Приросту інформації (Information Gain)**, який є ентропією батьківського вузла мінус зважена середня ентропія дочірніх вузлів: $$IG = H(\text{parent}) - \sum_{c \in \{\text{left, right}\}} \frac{N_c}{N} H(c)$$
Обидва показники досягають 0, коли вузол є повністю чистим (усі зразки належать до одного класу), і досягають свого максимуму, коли класи розподілені рівномірно.
6Що таке метод k-найближчих сусідів (kNN), і як він робить прогнози для класифікації та регресії?
Метод k-найближчих сусідів (kNN) — це непараметричний, заснований на екземплярах (лінивий) алгоритм навчання з учителем. Він не навчає явну параметричну модель; натомість, він зберігає навчальний набір даних і виконує всі обчислення під час виведення.
**Робочий процес прогнозування:**
1. **Обчислення відстані:** Коли оцінюється запитуваний екземпляр, алгоритм обчислює його відстань до всіх збережених навчальних екземплярів, використовуючи задану метрику (таку як Евклідова, Манхеттенська або Мінковського відстань).
2. **Вибір сусідів:** Він вибирає $k$ навчальних екземплярів з найменшими відстанями до запитуваного екземпляра.
3. **Агрегація:**
* **Класифікація:** Присвоює клас шляхом голосування більшості (моди) серед $k$ сусідів (або голосування зваженого за відстанню).
* **Регресія:** Прогнозує неперервне цільове значення, беручи локальне середнє (середнє арифметичне або медіану) цільових значень $k$ сусідів (або середнє зважене за відстанню).
Оскільки обчислення відстаней безпосередньо залежать від масштабів ознак, нормалізація або стандартизація ознак є важливою для запобігання домінування ознак великої величини в обчисленнях відстаней.
7Викладіть припущення про умовну незалежність наївного баєсівського класифікатора та поясніть, чому наївний Баєс все ще може добре працювати, коли воно порушується.
Припущення про умовну незалежність наївного баєсівського класифікатора стверджує, що, за наявності мітки класу Y = y, усі ознаки X_1, X_2, ..., X_d є взаємно незалежними: P(X_1, ..., X_d | Y = y) = \prod_{j=1}^d P(X_j | Y = y). Використовуючи теорему Баєса, апостеріорна ймовірність становить: P(Y = y | X) \propto P(Y = y) \prod_{j=1}^d P(X_j | Y = y), де P(Y = y) — апріорна ймовірність класу, а P(X_j | Y = y) — умовна ймовірність (правдоподібність) за класом (наприклад, Гауссівський розподіл для неперервних ознак, Мультиноміальний розподіл для підрахунків). Наївний Баєс часто добре працює на практиці, незважаючи на порушення незалежності, оскільки класифікація базується на правилі прийняття рішень argmax (argmax_y P(Y=y | X)), а не на точній калібровці ймовірностей. Навіть якщо кореляції ознак призводять до того, що передбачені ймовірності стають надмірно впевненими або спотвореними, правильний клас часто зберігає найвищий відносний ранг. Допоки кореляція не змінює порядок рангів правдоподібностей класів, рішення класифікації 0-1 залишається точним.
from sklearn.naive_bayes import GaussianNB
import numpy as np
X = np.array([[1.0, 1.1], [1.2, 0.9], [-1.0, -1.2], [-0.8, -1.1]])
y = np.array([1, 1, 0, 0])
model = GaussianNB()
model.fit(X, y)
# Prediction uses argmax over class posterior scores
print("Predicted class:", model.predict([[1.1, 1.0]]))
8Виведіть або поясніть аналітичне рішення OLS (Ordinary Least Squares - метод найменших квадратів) і вкажіть, коли воно існує єдиним чином.
Функція цілі методу найменших квадратів (OLS) мінімізує суму квадратів залишків:
$S(\beta) = \|y - X\beta\|^2 = (y - X\beta)^T (y - X\beta) = y^T y - 2\beta^T X^T y + \beta^T X^T X \beta$.
Прирівнювання градієнта відносно $\beta$ до нуля:
$$\nabla_\beta S(\beta) = -2 X^T y + 2 X^T X \beta = 0 \implies X^T X \beta = X^T y$$
Це нормальні рівняння. Коли $X^T X$ є невиродженою (оборотною), єдине аналітичне рішення має вигляд:
$$\hat{\beta} = (X^T X)^{-1} X^T y$$
Геометрично, $\hat{y} = X\hat{\beta} = X(X^T X)^{-1} X^T y = H y$ представляє ортогональну проєкцію цільового вектора $y$ на стовпцевий простір матриці планування $X$, де $H$ — це матриця проєкції ("шапки"). Рішення існує єдиним чином тоді і тільки тоді, коли $X^T X$ є оборотною, що вимагає, щоб матриця планування $X$ розміром $N \times P$ мала повний стовпцевий ранг ($Rank(X) = P$). Це вимагає $N \ge P$ і відсутності точної мультиколінеарності (жодна ознака не є лінійною комбінацією інших). Якщо $X$ має дефіцит рангу, $X^T X$ є виродженою, що призводить до нескінченної кількості рішень, які часто вирішуються за допомогою регуляризації або псевдооберненої матриці Мура-Пенроуза $X^+ y$.
import numpy as np
# Design matrix X (with intercept column) and target y
X = np.array([[1, 1], [1, 2], [1, 3], [1, 4]])
y = np.array([2.1, 3.9, 6.2, 8.0])
# Normal equations: (X^T X)^(-1) X^T y
beta_hat = np.linalg.inv(X.T @ X) @ X.T @ y
H = X @ np.linalg.inv(X.T @ X) @ X.T
y_hat = H @ y
print(f"Beta: {beta_hat}")
print(f"Predictions: {y_hat}")
9Що таке оцінка максимальної правдоподібності, і як вона призводить до функції втрат крос-ентропії в логістичній регресії?
Оцінка максимальної правдоподібності (Maximum Likelihood Estimation, MLE) — це метод оцінки параметрів моделі $\theta$ шляхом вибору значень, які максимізують правдоподібність $L(\theta) = P(\mathcal{D}|\theta)$ спостереженого набору даних. У бінарній логістичній регресії кожна мітка $y_i \in \{0, 1\}$ моделюється як незалежна випадкова величина Бернуллі, обумовлена $x_i$, з ймовірністю успіху $p_i = \sigma(w^T x_i + b)$. Функція маси ймовірності для спостереження $i$ дорівнює $P(y_i|x_i) = p_i^{y_i} (1 - p_i)^{1 - y_i}$. Припускаючи, що вибірки є незалежними та однаково розподіленими (i.i.d.), спільна правдоподібність дорівнює:
$$L(w, b) = \prod_{i=1}^N p_i^{y_i} (1 - p_i)^{1 - y_i}$$
Взяття натурального логарифма перетворює добуток у обчислювально зручну суму лог-правдоподібностей:
$$\ell(w, b) = \sum_{i=1}^N \left[ y_i \ln(p_i) + (1 - y_i) \ln(1 - p_i) \right]$$
Оскільки алгоритми оптимізації зазвичай формулюються як задачі мінімізації, ми заперечуємо лог-правдоподібність і нормалізуємо за розміром вибірки $N$, отримуючи Від'ємну лог-правдоподібність (Negative Log-Likelihood, NLL), яка є точно функцією втрат бінарної крос-ентропії (логарифмічні втрати):
$$J(w, b) = -\frac{1}{N} \sum_{i=1}^N \left[ y_i \ln(p_i) + (1 - y_i) \ln(1 - p_i) \right]$$
Ця функція втрат є опуклою (convex) відносно лінійних логітів/ваг, тому відповідні чисельні розв'язувачі оптимізують глобальний оптимум. Строга опуклість та скінченна унікальна оцінка MLE вимагають додаткових умов, таких як достатній ранг ознак, регуляризація та відсутність ідеального розділення класів.
10Як градієнтний спуск оптимізує класичну цільову функцію машинного навчання (МН), і як швидкість навчання, збіжність та опуклість впливають на навчання?
Градієнтний спуск мінімізує емпіричну функцію втрат, ітеративно оновлюючи параметри моделі у напрямку, протилежному градієнту цільової функції відносно цих параметрів: $\theta_{t+1} = \theta_t - \eta \nabla L(\theta_t)$. Ключові фактори, що впливають на навчання, включають: 1. Швидкість навчання ($\eta$): Контролює розмір кроку. Якщо її встановлено занадто малою, збіжність є надзвичайно повільною, і навчання може зупинитися. Якщо її встановлено занадто великою, оновлення перевищать мінімум, що спричинить осциляцію або числову розбіжність. 2. Збіжність: Визначається моніторингом критеріїв зупинки, таких як мала норма градієнта ($||\nabla L(\theta)|| \le \epsilon$), мінімальна зміна параметрів або плато функції втрат протягом послідовних ітерацій. 3. Опуклість: В опуклих цільових функціях (наприклад, стандартна лінійна регресія методом найменших квадратів (OLS) або логістична регресія) будь-який локальний мінімум гарантовано є глобальним мінімумом, що дозволяє градієнтному спуску надійно збігатися з відповідними розмірами кроку. У неопуклих цільових функціях (наприклад, багатошарові нейронні мережі) ландшафт функції втрат містить множинні локальні мінімуми, сідлові точки та плато, що робить кінцеве рішення чутливим до ініціалізації. 4. Оптимізація проти узагальнення: Збіжність за втратами на навчальних даних відображає успіх оптимізації, тоді як втрати на валідаційних даних оцінюють узагальнення. Досягнення низьких втрат на навчальних даних з високою помилкою валідації вказує на перенавчання, а не на невдачу оптимізації.
import numpy as np
def gradient_descent(X, y, lr=0.01, max_iters=1000, tol=1e-6):
n_samples, n_features = X.shape
theta = np.zeros(n_features)
prev_loss = float('inf')
for i in range(max_iters):
predictions = X @ theta
error = predictions - y
loss = (1 / (2 * n_samples)) * np.dot(error, error)
if abs(prev_loss - loss) < tol:
print(f'Converged at iteration {i}')
break
prev_loss = loss
grad = (1 / n_samples) * (X.T @ error)
theta -= lr * grad
return theta
11Порівняйте L1, L2 та регуляризацію ElasticNet з точки зору розрідженості, корельованих ознак та практичного вибору моделі.
L1 (Lasso), L2 (Ridge) та регуляризація ElasticNet відрізняються формулюванням штрафу, геометрією обмежень, розрідженістю та обробкою корельованих предикторів:
1. **Розрідженість та геометрія:**
* L1 використовує штраф абсолютного значення ($\lambda \|w\|_1$). Його межа обмеження є ромбом/політопом з гострими вершинами на координатних осях. Коли контури втрат перетинають ці кути, ваги доводяться до точного нуля, виконуючи автоматичний відбір ознак.
* L2 використовує штраф квадрата евклідової норми ($\lambda \|w\|_2^2$). Його межа обмеження є гладкою гіперсферою без кутів, що асимптотично зменшує ваги до нуля, але рідко встановлює їх на точний нуль.
2. **Корельовані ознаки:**
* За сильної колінеарності L1 схильний довільно обирати одну ознаку з групи корельованих предикторів і встановлювати інші коефіцієнти на нуль, що призводить до нестабільних оцінок при повторній вибірці.
* L2 зберігає всі корельовані ознаки, розподіляючи ваги між ними та стискаючи їх разом.
3. **ElasticNet:**
* Поєднує обидва штрафи: $\lambda_1 \|w\|_1 + \lambda_2 \|w\|_2^2$ (часто параметризується за допомогою $\alpha$ та $l_1\_\text{ratio}$).
* Забезпечує розрідженість та відбір ознак Lasso, зберігаючи при цьому ефект групування Ridge, вибираючи кластери корельованих предикторів разом. Це особливо корисно, коли $p > N$ або за сильної мультиколінеарності.
12У чому полягає різниця між Ridge-регресією, регресією за головними компонентами (Principal Component Regression) та частковими найменшими квадратами (Partial Least Squares) на високому рівні?
Ridge-регресія, регресія за головними компонентами (Principal Component Regression, PCR) та часткові найменші квадрати (Partial Least Squares, PLS) — це три лінійні методи, які використовуються для обробки мультиколінеарності та високої розмірності, але вони відрізняються тим, як вони зменшують дисперсію та чи є це зменшення неперервним або навчаним:
1. **Ridge-регресія**: Зберігає всі оригінальні $p$ ознак і застосовує неперервне стиснення до величин коефіцієнтів за допомогою L2-штрафу. Вона не створює латентних компонентів меншої розмірності та не відкидає виміри ознак; натомість, вона стискає дисперсію вздовж напрямків з низькими власними значеннями $X^T X$.
2. **Регресія за головними компонентами (PCR)**: Двоетапний, ненавчаний метод зменшення розмірності. Спочатку він застосовує аналіз головних компонентів (Principal Component Analysis, PCA) виключно до матриці предикторів $X$ для знаходження ортогональних напрямків максимальної дисперсії, зберігає $k$ головних компонентів і підганяє OLS-регресію (Ordinary Least Squares) на цих $k$ компонентах. Оскільки PCA ігнорує цільову змінну $y$, PCR ризикує відкинути компоненти, які мають низьку дисперсію в $X$, але високу прогностичну силу для $y$.
3. **Часткові найменші квадрати (PLS)**: Навчаний метод зменшення розмірності. Він конструює $k$ ортогональних латентних компонентів, знаходячи лінійні комбінації $X$, які максимізують коваріацію між $X$ і змінною відгуку $y$. Явно включаючи інформацію про цільову змінну, PLS ідентифікує компоненти, які пояснюють як дисперсію ознак, так і варіацію відгуку.
from sklearn.linear_model import Ridge, LinearRegression
from sklearn.decomposition import PCA
from sklearn.cross_decomposition import PLSRegression
from sklearn.pipeline import make_pipeline
# 1. Ridge: Regularized full feature space
ridge = Ridge(alpha=1.0)
# 2. PCR: Unsupervised PCA followed by OLS
pcr = make_pipeline(PCA(n_components=2), LinearRegression())
# 3. PLS: Supervised latent component projection and regression
pls = PLSRegression(n_components=2)
13Як сучасні реалізації градієнтного бустингу, такі як XGBoost, LightGBM та CatBoost, оптимізують навчання або по-різному обробляють табличні ознаки?
Сучасні фреймворки GBDT (Gradient Boosting Decision Tree) суттєво відрізняються алгоритмами пошуку розбиття, стратегіями росту дерева та обробкою табличних/категоріальних ознак:
1. **XGBoost:** Традиційно покладається на точний жадібний або приблизний квантильний скетч-пошук розбиття (а пізніше Fast Hist), використовує пошаровий (за глибиною) ріст дерева та обробляє відсутні значення, навчаючись оптимального напрямку гілки за замовчуванням під час пошуку розбиття.
2. **LightGBM:** Використовує пошук розбиття на основі гістограм (групування неперервних ознак у дискретні відра (bins), зазвичай 256), ріст дерева по листу (спочатку найкращі) для швидшого зменшення втрат, однобічну вибірку на основі градієнта (GOSS) для збереження екземплярів з великим градієнтом при під-вибірці екземплярів з малим градієнтом, та об'єднання ексклюзивних ознак (EFB) для злиття взаємовиключних розріджених ознак. Для категоріальних змінних він знаходить оптимальні розбиття шляхом сортування відер категоріальних гістограм ($O(K \log K)$).
3. **CatBoost:** Використовує невражаючі (симетричні) дерева рішень, де всі вузли на заданій глибині мають однакове розбиття, що забезпечує швидке векторизоване обчислення на ЦП/ГП. Його головна інновація — це упорядкована цільова статистика та упорядкований бустинг, який обчислює цільову статистику на випадкових перестановках навчальних даних для запобігання витоку цільової інформації та зсуву прогнозу.
14Як би ви вирішили, чи доцільна користувацька функція втрат для моделі градієнтного бустингу за умов асиметричних бізнес-витрат?
Вирішення питання про доцільність впровадження користувацької функції втрат у градієнтному бустингу за умов асиметричних бізнес-витрат вимагає оцінки того, чи може асиметрія бути оброблена на подальших етапах за допомогою калібрування ймовірностей та налаштування порогу, або ж вона принципово змінює оптимізаційний ландшафт під час побудови дерев:
1. **Налаштування порогу проти користувацької функції втрат**: Для завдань класифікації з асиметричними витратами на помилки (наприклад, хибнонегативні результати коштують у 10 разів дорожче за хибнопозитивні) стандартна крос-ентропія є правильною оціночною функцією, яка має на меті оцінку апостеріорних ймовірностей $P(y=1|x)$, але калібрування слід перевірити і, за потреби, скоригувати на валідаційних даних. Зсув порогу прийняття рішення класифікації на основі матриці бізнес-витрат $\tau = \frac{C_{FP}}{C_{FP} + C_{FN}}$ або застосування ваг зразків часто є чистішим рішенням і дозволяє уникнути користувацьких похідних. Однак, для асиметричної регресії (наприклад, асиметрична функція втрат pinball для попиту на запаси) або нелінійних бізнес-штрафів, де стандартні цільові функції не можуть керувати пошуком розщеплень, користувацька функція втрат є виправданою.
2. **Математичні вимоги для GBDT (Gradient Boosting Decision Tree)**: У бустерах другого порядку (XGBoost, LightGBM) користувацька функція втрат $L(y, \hat{y})$ зазвичай вимагає обчислюваних градієнтів першого порядку ($g_i = \partial L / \partial \hat{y}_i$) та дійсних значень кривизни/Гессіана другого порядку ($h_i = \partial^2 L / \partial \hat{y}_i^2$) для розрахунків приросту при розщепленні та ваг листя ($w^* = -\sum g_i / (\sum h_i + \lambda)$). Значення Гессіана повинні бути невід'ємними або безпечно апроксимовані/обмежені для числової стабільності; деякі реалізації підтримують цільові функції першого порядку або апроксимовані цільові функції, тому вимога залежить від фреймворку. Недиференційовані або розривні бізнес-метрики слід замінити гладкими сурогатними апроксимаціями (наприклад, Huber-подібними або log-cosh варіантами).
import numpy as np
import xgboost as xgb
def asymmetric_mse_objective(preds, dtrain):
labels = dtrain.get_label()
residual = preds - labels
# Penalize underestimation (residual < 0) 5x more heavily than overestimation
penalty = np.where(residual < 0, 5.0, 1.0)
grad = 2.0 * penalty * residual
hess = 2.0 * penalty
return grad, hess
# Usage:
# model = xgb.train(params, dtrain, obj=asymmetric_mse_objective)
15Що таке LambdaMART, і як він адаптує градієнтний бустинг для завдань навчання ранжуванню?
LambdaMART — це алгоритм навчання ранжуванню (LTR), який поєднує MART (багатократні адитивні регресійні дерева / градієнтний бустинг) з фреймворком LambdaRank. У ранжуванні цільові метрики, такі як NDCG (Normalized Discounted Cumulative Gain — нормалізований дисконтований кумулятивний приріст) та MAP (Mean Average Precision — середня точність), залежать від дискретного порядку сортування (рангів), що робить їх майже всюди «плоскими» та недиференційованими відносно безперервних оцінок моделі. LambdaMART обходить це, конструюючи віртуальні градієнти, що називаються 'лямбда-градієнтами' ($\lambda_{ij}$), для пар елементів $(i, j)$ в межах одного запиту. Базовий попарний градієнт походить від логістичної функції втрат (logistic loss) на різницях оцінок ($s_i - s_j$). LambdaMART масштабує цей градієнт на точну зміну цільової метрики ранжування ($|\Delta \text{NDCG}_{ij}|$), яка відбулася б, якби позиції документа $i$ та документа $j$ були поміняні місцями: $$\lambda_{ij} = \frac{-\sigma}{1 + e^{\sigma(s_i - s_j)}} |\Delta \text{NDCG}_{ij}|$$ Для кожного окремого документа $i$ сумарний градієнт обчислюється шляхом агрегування попарних лямбда-значень для всіх пар, що включають документ $i$: $\lambda_i = \sum_{j: j \succ i} \lambda_{ij} - \sum_{k: i \succ k} \lambda_{ki}$. Стандартні регресійні дерева в бустинговому ансамблі потім адаптуються до цих складових лямбда-градієнтів для кожного документа на кожній ітерації бустингу, безпосередньо оптимізуючи метрики ранжування в масштабі списку.
import lightgbm as lgb
import numpy as np
# Simulated query-grouped data: 2 queries with 3 docs each
X = np.random.randn(6, 10)
y = np.array([3, 1, 0, 2, 0, 1]) # Relevance grades (0-3)
group = [3, 3] # Query group sizes
train_data = lgb.Dataset(X, label=y, group=group)
params = {
'objective': 'lambdarank',
'metric': 'ndcg',
'ndcg_eval_at': [1, 3],
'learning_rate': 0.1,
'n_estimators': 50
}
ranker = lgb.train(params, train_data)