Как ментальные модели и математика помогают решать задачи программистам

О чем будет в статье

  • Рассмотрим процесс поиска решения инженером на примере из реального мира. Подумаем о том, как к этому процессу системнее подойти.
  • Покажем, как умение проводить аналогии из других областей знаний помогает в этом процессе. И при чем здесь ментальные модели.
  • Увидим, как даже базовые математические знания помогают в решении практических задач.
  • И заодно узнаем, как IMDB сортирует свой топ фильмов :)
Как ментальные модели и математика помогают решать задачи программистам

🎯 Задача / Расставляем номера в отеле на уборку

Итак, мы хотим автоматизировать постановку номеров отеля на уборку. Это важный операционный процесс, поскольку плохой план уборки может привести к проблемам сервиса и снижению лояльности гостей.

Вот несколько ситуаций разной критичности, которых отель не должен допускать:

  • Заезжающие вечером гости не должны ожидать уборки своих номеров, которые освободились в этот же день утром.
  • Номера VIP-гостей должны убираться первым приоритетом, даже если отель полностью загружен гостями, и сегодня очень много выездов и заездов
  • Не должны пропускаться персональные просьбы гостей провести им сегодня уборку

Удерживать в голове все эти правила и выставить более сотни номеров в верном порядке на уборку - задача не простая. Давайте поможем руководителю номерного фонда!

🧠 Как будем искать решение? Вооружимся принципами и ментальными моделями

Можно побежать писать код с условиями “если заезжает VIP-гость…” после вводных выше. Можно попытаться решить задачу чуть более абстрактно, чтобы логика выстраивания приоритетов поддавалась настройке. Можно вооружиться аппаратом машинного обучения. И в разных контекстах каждая из этих стратегий может оказаться более оптимальной.

💡 Есть полезный принцип, который помогает системнее подходить к решению задач. Назовем его “сначала сделай шаг наверх”. Если более полно - “исследуй проблему, пойми что решать, пойми возможные решения, реализуй наиболее подходящее”

Принцип не придуман из воздуха, многие известные модели поиска и принятия решений предлагают именно такой подход, например модель двойного алмаза от British Design Council и антропоцентрический дизайн IDEO.

Модель двойного алмаза
Модель двойного алмаза
Модель антропоцентрического дизайн-процесса
Модель антропоцентрического дизайн-процесса

Поэтому, начнем с обогащения контекста.

👀 Обогащаем контекст, определяем варианты решений

Каждый номер может обладать рядом признаков, которые влияют на приоритет уборки. Номер может иметь одновременно несколько признаков. Важность признаков разная.

Вооружаемся шириной своих знаний, Google и СhatGPT. Попробуем составить список похожих задач из других предметных областей и понять общие схемы их решений.

Google Analytics - Estimated True Value (ETV)

На ключевой параметр (например процент сбоев на странице) влияет другой параметр (кол-во просмотров этой страницы), использующийся в качестве “веса” при сортировке по статистически значимым значениям.

Формула для расчета значения выглядит следующим образом:

S = (F2 / F2_max * F1) + ((1 - (F2 / F2_max)) * F1_avg) F1 - интересующая нас метрика F2 - вторичный параметр, определяющий статистическую значимость

Вычисление специфичности CSS-стилей, текстовый поисковый движок Lucene - взвешенные многопараметрические суммы

S = (w1 * F1) + (w2 * F2) + (w3 * F3)

Простая сумма произведений параметров на их веса.

В CSS разным видам селекторов заданы фиксированные веса. Это позволяет очень гибко задавать разные стили на уровне html-элементов, классов, id или на уровне конечного DOM-элемента. Например, позволяет один раз описать для всех -ов их общие стили, а отличающиеся детали описывать уже на уровне конкретных элементов в конкретных местах сайта или приложения.

Веса разных CSS селекторов при расчете специфичности стиля
Веса разных CSS селекторов при расчете специфичности стиля

Lucene использует технику TF-IDF (Term Frequency - Inverse Document Frequency) чтобы назначить веса каждому слову в каждом документе. Каждый текстовый документ представляется вектором TF-IDF весов для каждого слова. Запросы к движку также представляются этим вектором. В N-мерном пространстве вычисляются углы между векторами документов и вектором запроса. Результаты сортируются по величине этого угла.

Рейтинг фильмов IMDB Top 250 - Байесовская оценка

weighted rating (WR) = (v ÷ (v+m)) × R + (m ÷ (v+m)) × C R = медианная оценка фильму v = кол-во голосов m = минимальное кол-во голосов чтобы попасть в рейтинг Top 250 (около 25000) C = медианная оценка среди всех фильмов в рейтинге (около 7.0)

Ранжирование в поисковых системах, социальных сетях, маркетплейсах - применение машинного обучения

Все примеры выше для получения сортирующей/ранжирующей функции использовали векторную модель вычисления. Мы приходили к какой-то фиксированной функции для вычисления скоринг-суммы каждого элемента и логике выбора коэффициентов для учета веса каждого влияющего на результат параметра.

Можно пойти другим путем - использовать модель машинного обучения для “предсказывания“ скоринг-сумм. Такая стратегия решения может оказаться полезной, когда мы не можем прийти к четкой и простой формуле, когда в системе сильно больше параметров, когда параметры и их влияние могут меняться со временем или в зависимости от входных данных. Decision trees, random forests, gradient boosting, and neural networks - можно обратиться к этим техникам. В рамках этой статьи углубляться в них не будем, поскольку наш кейс кажется недостаточно комплексным, чтобы решать его этим путем.

🎯 Выбираем вариант, ищем лучшую реализацию, используем математику!

💡 Включаем еще один важный принцип при принятии решений - верный баланс. Найдем удачный баланс между сложностью, точностью и гибкостью алгоритма.

Находим баланс

Допустим мы установили, что приоритет номера к уборке зависит только от его параметров, и не зависит от состояния других номеров или прочих внешних обстоятельств. В таком случае наиболее близким по смыслу кажется пример с расчетом CSS-специфичности.

S = (w1 * F1) + (w2 * F2) + (w3 * F3)

Отлично, мы выбрали алгоритм решения! Осталось понять, по какой логике назначить вес каждого параметра.

Изучаем предметную область чуть глубже, задаемся вопросом: насколько для ранжирования уборки номера важен каждый из его параметров - факт проживания VIP-гостя, факт того что сегодня из номера будет выезжать текущий гость и заезжать следующий, и тд.

Допустим, мы установили два момента:

  • всегда есть строгий порядок от более важного признака к менее важному, но между разными отелями этот порядок может отличаться
  • если номер обладает более важным признаком, то даже одновременное наличие всех остальных признаков не делает уборку более важной (и это справедливо для каждого признака). Например если номер выехал и ожидается заезд, то уборку надо делать сначала там, даже если в другом номере проживает VIP гость, и он повесил табличку “просьба убрать номер”.

Из первого момента можно принять решение, что отелю стоит иметь настраиваемый список приоритетов, где можно задавать их порядок. Также это означает, что мы не можем просто написать логику из вложенных условий, придется высчитывать вес каждого параметра.

Используем математику

Второй момент нам позволит подобрать правильную функцию для назначения весов, используя святые знания математики, а именно знания о росте функций.

Если номер имеет один первый признак, а второй номер имеет все остальные признаки, то первый номер все равно должен оказаться выше. Значит сумма всех весов, начиная со второго, должна быть меньше первого признака. И это справедливо для каждой позиции.

Похоже нам нужна строго монотонная, возрастающая функция. Более того, можно взять степенную функцию, чтобы гарантированно каждое ее значение было больше суммы предыдущих (а так и будет, ведь возведение в степень 2 это уже сложение числа N - N раз; и это даст большую сумму чем сложение N чисел, меньших чем текущее).

Какая функция растет быстрее линейной? Степенная!
Какая функция растет быстрее линейной? Степенная!

Далеко не отходя, возьмем функцию 2^x.

1 2 4 8 16 32 - каждое из чисел больше суммы предыдущих

  • берем расставленные по порядку признаки, влияющие на уборку
  • выдаем им веса по найденной нами функции
  • вычисляем для каждого номера суммарный вес
  • сортируем номера по весу
  • можно идти убирать номера ⭐

🧘 Подводим итоги

Иногда говорят: “не обязательно знать [вставь любую дисциплину], чтобы уметь программировать”. Процесс решения проблемы в данной статье может послужить примером обратного тезиса - чем больше ментальных моделей ты сможешь собрать из разных предметных областей и научиться применять, тем более комплексно они могут помогать в решении задач.

Модель дизайн мышления “двойной бриллиант” или теория решения изобретательских задач помогут правильно идентифицировать проблему и не застревать в решениях “в лоб”.

“Насмотренность” в разных предметных областях и навыки поиска информации помогут расширить взгляд на проблему и увидеть паттерны решения подобных задач.

Знания математики часто выручают при проектировании систем (идемпотентность правит при проектировании информационных систем и заслуживает отдельной статьи). Базовые знания о росте функций помогли нам быстро выбрать верные веса признаков для сортировки. Машинное обучение неразрывно со статистикой.

55