Допущения, валидность и границы применимости
Урок про самое важное и самое игнорируемое: допущения модели и границы, за которыми ей нельзя верить.
Допущение — упрощающее предположение, которое модель принимает как истину; область применимости — множество ситуаций, где эти допущения достаточно близки к реальности.
«Все модели неверны, но некоторые полезны»
Эту фразу статистика Джорджа Бокса стоит выучить наизусть. Она означает: не существует «правильной» модели, потому что любая модель упрощает, а значит, в чём-то лжёт. Спрашивать «верна ли модель?» бессмысленно. Осмысленный вопрос — «полезна ли она для моей задачи и где проходят её границы?».
Модель идеального газа PV = nRT «неверна»: молекулы имеют размер и притягиваются. Но для воздуха при комнатных условиях она полезна до третьего знака. А вот для газа под огромным давлением она ломается — там нужна модель сложнее. Та же формула: внутри своей области применимости — полезна, снаружи — опасна.
Откуда берутся допущения
Каждое упрощение при формализации — это допущение. Полезно выписывать их явным списком. Для модели эпидемии типичные допущения:
- популяция перемешана однородно (каждый может встретить каждого);
- заразность одинакова у всех и не меняется во времени;
- переболевший получает пожизненный иммунитет;
- рождений и смертей за время эпидемии нет.
Ни одно из них не верно буквально. Но если эпидемия короткая и идёт в небольшом городе, они достаточно близки к правде, и модель работает. Перенесите её на год и на страну с регионами — и однородность перемешивания сломается первой.
Чувствительность к допущениям
Не все допущения одинаково опасны. Одни почти не влияют на ответ, другие определяют его целиком. Хороший способ это проверить — пошевелить допущение и посмотреть, как сильно дёрнется результат.
# как допущение о заразности влияет на размер эпидемии
def final_size(beta, gamma=0.1):
S, I, R, N = 999.0, 1.0, 0.0, 1000.0
for _ in range(300):
new_inf = beta * S * I / N
new_rec = gamma * I
S -= new_inf
I += new_inf - new_rec
R += new_rec
return R # сколько всего переболело
print(f"{'beta':>5} {'R0':>4} {'переболело':>11}")
for beta in (0.12, 0.15, 0.20, 0.30):
print(f"{beta:>5.2f} {beta/0.1:>4.1f} {final_size(beta):>11.1f}")
Вывод:
beta R0 переболело 0.12 1.2 270.5 0.15 1.5 586.6 0.20 2.0 802.8 0.30 3.0 946.7
Видно, что небольшое изменение допущения о заразности (с 0.12 до 0.30) меняет ответ в три раза — с трети населения до почти всех. Значит, это допущение критично, и его надо обосновывать тщательно. А вот точное начальное число больных (1 или 10) на финальный размер почти не влияет — это допущение «дешёвое».
Как работает под капотом
Граница применимости — не абстракция, она кодируется. Хорошая модель проверяет входы и честно отказывается работать вне области: если dt слишком велик, если число особей стало отрицательным, если параметр вне разумного диапазона. Молчаливое продолжение счёта за границей применимости — источник красивых, убедительных и совершенно ложных результатов. Лучше упасть с ошибкой, чем выдать правдоподобную чушь.
Частые ошибки
- Не выписывать допущения. Если список допущений живёт только в голове автора, модель невозможно ни проверить, ни безопасно переиспользовать.
- Применять модель вне её области. Формула, отличная для воздуха, врёт для плазмы. Перенос модели в новый режим без проверки — классическая катастрофа.
- Считать все допущения равноценными. Без анализа чувствительности вы тратите силы на уточнение неважного и упускаете критичное.
Итоги
- Любая модель держится на допущениях и потому «неверна»; вопрос — полезна ли она в своей области применимости.
- Допущения стоит выписывать явным списком, иначе модель нельзя проверить и безопасно переиспользовать.
- Чувствительность к допущению проверяют, шевеля его и наблюдая за ответом: критичные требуют обоснования, «дешёвые» — нет.
- Границу применимости полезно кодировать как явные проверки, а не надеяться на удачу.