Перейти к содержимому

Формула Байеса на пальцах

Если ты увидишь страшную формулу

P(Lcorrect)=P(L)(1P(S))P(L)(1P(S))+(1P(L))P(G)P(L \mid \text{correct}) = \frac{P(L) \cdot (1 - P(S))}{P(L) \cdot (1 - P(S)) + (1 - P(L)) \cdot P(G)}

и захочешь убежать — спокойно. Сейчас разберём её на пальцах. По сути, это здравый смысл, записанный в виде дроби.

Формула Байеса отвечает на вопрос:

Я думал, что событие A вероятно с такой-то частотой. Потом увидел наблюдение B. Как мне обновить свою оценку A?

В нашем случае:

  • A = «ученик овладел навыком»
  • B = «ученик решил задачу правильно»

Мы хотим вычислить P(AB)P(A \mid B) — вероятность A при условии B.

Представим, что мы сами не знаем — знает ли ученик навык. Поделим учеников на две коробки:

%%{init: {'theme': 'base','flowchart': {'nodeSpacing': 96,'rankSpacing': 108,'padding': 40,'curve': 'basis','useMaxWidth': true}}}%%
flowchart LR
Pop["Совокупность (1.0)"]
Pop -->|"P(L)"| K[Знают навык]
Pop -->|"1 - P(L)"| NK[Не знают]
K -->|"1 - P(S)"| KR[Знает и верно]
K -->|"P(S)"| KW[Знает, ошибся slip]
NK -->|"P(G)"| NKR[Не знает, угадал]
NK -->|"1 - P(G)"| NKW[Не знает, не угадал]
Дерево вероятностей: каждый ученик попадает в одну из 4 ячеек

Если поставить численные значения:

  • P(L)=0.2P(L) = 0.2 → 20% «знают», 80% «не знают»;
  • P(S)=0.1P(S) = 0.1 → из «знающих» 90% решат правильно, 10% «оплошают»;
  • P(G)=0.2P(G) = 0.2 → из «не знающих» 20% угадают, 80% ошибутся.

Получаем 4 ячейки:

Решит правильноРешит неправильно
Знает (P(L)=0.2P(L)=0.2)0.20.9=0.180.2 \cdot 0.9 = 0.180.20.1=0.020.2 \cdot 0.1 = 0.02
Не знает (1P(L)=0.81-P(L)=0.8)0.80.2=0.160.8 \cdot 0.2 = 0.160.80.8=0.640.8 \cdot 0.8 = 0.64
Сумма0.340.66

Сумма всех ячеек = 1.001.00 — это полная вероятность.

Когда мы наблюдаем «правильно решил», мы переключаемся в столбец «решит правильно» — итого 0.34 на всех учеников.

Из этих 0.34, какая доля приходится на «знающих»?

P(знаетрешил правильно)=0.180.34=0.529P(\text{знает} \mid \text{решил правильно}) = \frac{0.18}{0.34} = 0.529

Это и есть формула Байеса — числитель «знает И решил», знаменатель «всего решивших».

В общем виде:

P(Lcorrect)=P(L)(1P(S))знал И не оплошалP(L)(1P(S))из знающих+(1P(L))P(G)из не знающих, угадавшихP(L \mid \text{correct}) = \frac{\overbrace{P(L) \cdot (1 - P(S))}^{\text{знал И не оплошал}}}{\underbrace{P(L) \cdot (1 - P(S))}_{\text{из знающих}} + \underbrace{(1 - P(L)) \cdot P(G)}_{\text{из не знающих, угадавших}}}

И аналогично для «неправильно»:

P(Lwrong)=P(L)P(S)P(L)P(S)+(1P(L))(1P(G))P(L \mid \text{wrong}) = \frac{P(L) \cdot P(S)}{P(L) \cdot P(S) + (1 - P(L)) \cdot (1 - P(G))}

Возьмём наш пример: P(L)=0.2P(L) = 0.2, P(S)=0.1P(S) = 0.1, P(G)=0.2P(G) = 0.2. Ученик ответил правильно.

P(Lcorrect)=0.20.90.20.9+0.80.2=0.180.18+0.16=0.180.340.529P(L \mid \text{correct}) = \frac{0.2 \cdot 0.9}{0.2 \cdot 0.9 + 0.8 \cdot 0.2} = \frac{0.18}{0.18 + 0.16} = \frac{0.18}{0.34} \approx 0.529

С 0.2 уверенность подскочила до 0.529 — почти «50/50, скорее знает».

Что если он ответил неправильно?

P(Lwrong)=0.20.10.20.1+0.80.9=0.020.02+0.72=0.020.740.027P(L \mid \text{wrong}) = \frac{0.2 \cdot 0.1}{0.2 \cdot 0.1 + 0.8 \cdot 0.9} = \frac{0.02}{0.02 + 0.72} = \frac{0.02}{0.74} \approx 0.027

Уверенность упала почти до нуля.

Почему модель так агрессивно «разыгрывается» на одной задаче

Заголовок раздела «Почему модель так агрессивно «разыгрывается» на одной задаче»

Заметь: при P(L0)=0.2P(L_0) = 0.2 ошибка роняет уверенность с 0.2 до 0.027 — почти в 8 раз. Это правильно:

Если мы и так почти не верили в Ваню, и он ошибся — это ровно то, что мы ожидали. Уверенность правильно укрепляется в направлении «не знает».

А вот при P(L)=0.95P(L) = 0.95 (мы уже уверены, что ученик знает) одна ошибка понижает P(L)P(L) только до ~0.61 — модель относится к этому как к slip’у и не паникует. Проверь сам:

P(Lwrong)=0.950.10.950.1+0.050.9=0.0950.095+0.0450.679P(L \mid \text{wrong}) = \frac{0.95 \cdot 0.1}{0.95 \cdot 0.1 + 0.05 \cdot 0.9} = \frac{0.095}{0.095 + 0.045} \approx 0.679

Это и есть умное обновление.

Шаг 2: дополнение «можно научиться по ходу»

Заголовок раздела «Шаг 2: дополнение «можно научиться по ходу»»

После применения формулы Байеса (мы её называем posterior) делаем ещё один маленький шаг:

P(Lnew)=Pposterior+(1Pposterior)P(T)P(L_{\text{new}}) = P_{\text{posterior}} + (1 - P_{\text{posterior}}) \cdot P(T)

Это значит:

Даже если posterior говорит, что ты не знал — у тебя был шанс научиться прямо в этой задаче с вероятностью P(T)P(T).

С P(T)=0.1P(T) = 0.1:

P(Lnew)=0.529+(10.529)0.10.576P(L_{\text{new}}) = 0.529 + (1 - 0.529) \cdot 0.1 \approx 0.576

И для случая «ошибся»:

P(Lnew)=0.027+(10.027)0.10.124P(L_{\text{new}}) = 0.027 + (1 - 0.027) \cdot 0.1 \approx 0.124

Это всё. Вся модель.

// Шаг 1. Posterior через формулу Байеса.
posterior = correct
? (pL * (1 - pSlip)) / (pL * (1 - pSlip) + (1 - pL) * pGuess)
: (pL * pSlip) / (pL * pSlip + (1 - pL) * (1 - pGuess));
// Шаг 2. Обновление с учётом возможности доучиться.
pL_new = posterior + (1 - posterior) * pTransit;

Ровно так это и реализовано в web/lib/bkt.ts — функция bktUpdate. См. главу с разбором кода.

Все 4 ячейки 2×2 таблицы — на одном квадрате. Двигай ползунки и нажимай кнопку «решил/ошибся». Подсветка покажет, какая часть «выживает» после наблюдения, и формула посчитает posterior.

«Все возможные исходы» (4 ячейки)
знаетне знает
Высота — P(L)/(1−P(L)). Ширина зелёного — «правильный». Заметные ячейки = наблюдение совпало.
P(L | ✓)
0.818
P(L | ✗)
0.111
posterior
0.818
сдвиг: +0.318

Это тот же Bayes step-by-step, что и сверху, только без алгебры — ты просто видишь, какая площадь соответствует наблюдению.

В следующей главе — обе формулы рядом и intuition pumps, в главе 7 — полный численный пример из 8 задач.