Лучший первый вопрос
Решающее дерево начинается с одного вопроса «x ≤ t?». Есть n примеров: у каждого числовой признак xi и ответ yi — 0 или 1. Вопрос делит примеры на две непустые группы, и хороший вопрос — тот, после которого неопределённость меньше всего. Найдите порог t с наибольшим приростом информации
$$\mathrm{IG} = H(\text{все}) - \frac{n_{\le}}{n}\,H(\text{группа } x \le t) - \frac{n_{>}}{n}\,H(\text{группа } x > t),$$где H — энтропия группы в битах: если в группе доля единиц p, то H = −p log₂ p − (1 − p) log₂ (1 − p) (слагаемое с нулевой долей считается нулём).
Два теста — землетрясения магнитудой от 5 за 2015–2021 годы из каталога USGS: признак — магнитуда (в сотых) или расстояние до ближайшего города от 10 тысяч жителей (км), ответ — сообщил ли кто-нибудь, что почувствовал толчок.
Вход
В первой строке n (2 ≤ n ≤ 200 000). В каждой из следующих n строк — целые xi (|xi| ≤ 10⁹) и yi ∈ {0, 1}.
Выход
Если все xi одинаковы, выведите -: ни один вопрос не делит примеры. Иначе выведите два числа: порог t и прирост информации. Подходит любой порог, при котором обе группы непустые и прирост отличается от наибольшего возможного не больше чем на 10⁻⁹; прирост проверяется с погрешностью 10⁻⁶.
Примеры
Пример 1
8 1 0 2 0 3 0 4 1 5 0 6 1 7 1 8 1
3.5 0.548794941
Пример 2
3 42 1 42 0 42 1
-
Ограничения
- Время · Python
- 6000 мс
- Время · Go
- 1500 мс
- Память
- 256 МБ
- Проверка
- 8 тестов
Разбор
Открывайте по ступеням: каждая следующая подсказывает больше. Можно сразу к решению — но задача, решённая с одной подсказкой, запоминается лучше.
1Подсказка 1
Порогов, которые стоит проверить, немного: вопрос «x ≤ t?» делит примеры одинаково при всех t между двумя соседними различными значениями x. Сколько различных делений бывает у n чисел?
2Подсказка 2
Для каждого деления нужны лишь размеры групп и число единиц в каждой. Если примеры отсортированы по x, как получить эти числа для следующего деления из предыдущего за O(1)?
3Идея
Сортируем примеры по x и идём слева направо, перенося по одному примеру из правой группы в левую и обновляя число единиц слева. Каждый раз, когда соседние значения различаются, перед нами одно из возможных делений: считаем для него прирост информации и запоминаем лучший. Порог — середина между соседними значениями; подойдёт и любое число между ними.
4Разбор
Энтропия всех примеров не зависит от вопроса, так что максимизировать прирост — то же, что минимизировать среднюю энтропию групп, взвешенную их размерами. Веса здесь главное: группа из одного примера всегда «чистая», её энтропия ноль, но описывает она один пример из тысячи.
Одинаковые x нельзя разделить: вопрос «x ≤ t?» отправляет их все в одну сторону. Поэтому деление между равными значениями пропускаем — иначе программа посчитает прирост для разбиения, которого не бывает. Если все x равны, делений нет вовсе.
На землетрясениях 2015–2021 годов лучший вопрос о расстоянии — «до города не больше 106,5 км?» с приростом 0,172 бита, а лучший вопрос о магнитуде — «магнитуда не больше 5,85?» с приростом всего 0,042. Поэтому дерево из статьи начинает с расстояния.
4+Решение
5Сложность
O(n log n) на сортировку и O(n) на проход. Перебор порогов с пересчётом групп заново — O(n²) — на двухстах тысячах примеров не успевает.
6Типичные ошибки
- Среднее энтропий без весов. Отрезанный крайний пример даёт чистую группу с нулевой энтропией, и такой «вопрос» побеждает. Седьмой тест построен на этом: одинокий пример на дальнем краю.
- Деление между равными значениями. Посчитанный прирост принадлежит невозможному разбиению, а выведенный порог даёт другое.
- log(0). Пустая доля в энтропии считается нулём: −0·log₂0 = 0 по непрерывности, а не ошибка вычисления.