Обеспеченность сервисами

Обзор

Анализ обеспеченности распределяет спрос зданий (например, число детей школьного возраста) между сервисами с ограниченной вместимостью (местами в школах) по матрице стоимостей пути между ними и нормативному порогу (минуты или метры). Он показывает, какие здания обслуживаются в пределах порога, какие — только более далёкими сервисами и какие сервисы перегружены или недогружены.

objectnat.get_service_provision() рассчитывает распределение и возвращает objectnat.ProvisionResult. Вспомогательные функции присоединяют показатели к зданиям и сервисам и строят геометрию связей; objectnat.recalculate_links() и objectnat.clip_provision() изменяют уже рассчитанный результат.

Входные данные

  • buildings: GeoDataFrame с числовым столбцом спроса (buildings_demand_column, по умолчанию "demand");

  • services: GeoDataFrame с числовым столбцом вместимости (services_capacity_column, по умолчанию "capacity");

  • distance_matrix: стоимости со строками buildings.index и столбцами services.index в единицах threshold. Это может быть плотный DataFrame (inf или NaN для недостижимых пар) или разреженный DataFrame pandas (SparseDtype с NaN или inf в качестве заполнителя), который хранит только достижимые пары. Разреженные матрицы читаются поэлементно без уплотнения, поэтому большие территории помещаются в памяти. Такую разреженную матрицу возвращает od_matrix из IduEdu (см. Матрица времени в пути от зданий до сервисов).

Метод

Распределение — гравитационная вероятностная модель; оно выполняется в расширении ObjectNat на Rust по элементам (разреженной) матрицы. Спрос могут получить только пары здание–сервис с конечной стоимостью d не больше 3 * threshold. У каждой такой пары есть гравитационный вес 1 / (d + 1)²: чем ближе здание, тем больше вес, и здание вдвое ближе получает в среднем примерно вчетверо больше. Единица прибавляется, чтобы здание с нулевой стоимостью, стоящее там же, где сервис, получало конечный вес. Распределение идёт раундами:

  1. Радиус поиска. Первый раунд рассматривает пары со стоимостью примерно до половины порога, (threshold + 1) / 2; каждый раунд расширяет этот радиус в 1,5 раза, поэтому ближние здания обслуживаются первыми.

  2. Предложения. Каждый сервис со свободными местами берёт здания с неудовлетворённым спросом внутри радиуса, оставляет из них здания с наибольшими весами (сначала верхнюю десятую часть; доля растёт по мере выбывания зданий и сервисов) и случайно распределяет между ними свободные места пропорционально весам.

  3. Принятие. Здание, получившее больше предложений, чем ему нужно, принимает свой неудовлетворённый спрос, случайно выбирая среди предложений пропорционально их размеру; остальные места остаются свободными.

  4. Следующий раунд. Здания без неудовлетворённого спроса и сервисы без свободных мест выбывают, и раунды продолжаются, пока распределять нечего.

Случайные последовательности инициализируются из seed отдельно для каждого объекта и итерации, поэтому при фиксированном seed результат одинаков при любом числе ядер процессора. Разные seed дают альтернативные распределения в рамках той же модели.

Результаты

objectnat.ProvisionResult содержит

  • flow: разреженную матрицу здание × сервис с распределённым спросом;

  • demand_rows: по каждому зданию demand, demand_left, supplied_demands_within и supplied_demands_without (спрос, полученный от сервисов в пределах / за пределами threshold), min_dist (стоимость пути до ближайшего сервиса), avg_dist (средняя стоимость, взвешенная по потокам) и provision_value = supplied_demands_within / demand;

  • capacity_rows: по каждому сервису capacity, capacity_left, carried_capacity_within, carried_capacity_without и service_load (суммарный распределённый спрос);

  • distance_matrix и threshold, использованные в расчёте.

objectnat.get_provision_buildings() и objectnat.get_provision_services() присоединяют эти показатели к копиям входных GeoDataFrame; objectnat.get_provision_links() возвращает по одной прямой на каждый ненулевой поток, от характерной точки здания к сервису, со столбцами building_index, service_index, demand (распределённые единицы) и distance (стоимость).

objectnat.get_service_provision(*, buildings, distance_matrix, services, threshold, buildings_demand_column='demand', services_capacity_column='capacity', seed=0)[исходный код]

Рассчитывает обеспеченность сервисами между точками спроса и объектами обслуживания.

Функция реализует гравитационную модель распределения: вместимость сервиса распределяется между ближними точками спроса с весами, которые убывают с квадратом расстояния (или обобщённой стоимости). Более близкие здания получают пропорционально большую долю доступной вместимости. В распределении участвуют только пары здание–сервис в пределах 3 * threshold; оно выполняется в расширении ObjectNat на Rust только по этим парам.

Параметры:
  • buildings (GeoDataFrame) – GeoDataFrame точек спроса. Должен содержать числовой столбец спроса.

  • distance_matrix (DataFrame) – Матрица стоимостей OD, строки которой — buildings.index, а столбцы — services.index. Единицы должны совпадать с threshold. Плотный DataFrame (inf/NaN — недостижимо) или, для больших территорий, разреженный DataFrame pandas (SparseDtype с заполнителем NaN или inf), который хранит только достижимые пары.

  • services (GeoDataFrame) – GeoDataFrame объектов обслуживания. Должен содержать числовой столбец вместимости.

  • threshold (float) – Нормативный порог стоимости. Единицы те же, что в distance_matrix.

  • buildings_demand_column (str) – Имя столбца со спросом зданий. По умолчанию "demand".

  • services_capacity_column (str) – Имя столбца с вместимостью сервисов. По умолчанию "capacity".

  • seed (int) – Начальное значение генератора случайных выборок при распределении. Фиксированное значение даёт воспроизводимый результат (независимо от числа ядер процессора); меняйте его, чтобы получить альтернативные распределения. По умолчанию 0.

Результат:

Dataclass с разреженной матрицей потоков здание–сервис, показателями зданий и сервисов, согласованной матрицей расстояний и нормативным порогом.

Тип результата:

ProvisionResult

class objectnat.ProvisionResult(flow, demand_rows, capacity_rows, distance_matrix, threshold)[исходный код]

Результат расчёта обеспеченности сервисами.

Параметры:
flow

Разреженная матрица распределения здание–сервис. Строки соответствуют индексам зданий, столбцы — индексам сервисов, ненулевые значения — распределённые единицы спроса.

demand_rows

Показатели зданий с индексом как у flow.index. Включают исходный спрос, оставшийся спрос, спрос, удовлетворённый в пределах и за пределами порога, стоимость пути до ближайшего сервиса, среднюю стоимость, взвешенную по потокам, и показатель обеспеченности.

capacity_rows

Показатели сервисов с индексом как у flow.columns. Включают исходную вместимость, оставшуюся вместимость, вместимость, отданную в пределах и за пределами порога, и суммарную нагрузку сервиса.

distance_matrix

Согласованная матрица стоимостей OD, использованная в расчёте (плотная или разреженная pandas, если была передана разреженная матрица). Её индекс и столбцы должны совпадать с flow.

threshold

Нормативный порог расстояния или времени, по которому потоки делятся на показатели в пределах и за пределами порога.

objectnat.get_provision_buildings(buildings_gdf, provision_result)[исходный код]

Присоединяет к зданиям показатели спроса из расчёта обеспеченности.

Существующие столбцы с теми же именами, что у показателей, удаляются и заменяются. Возвращаемый объект сохраняет тип и индекс входных данных.

Тип результата:

GeoDataFrame | DataFrame

Параметры:
objectnat.get_provision_services(services_gdf, provision_result)[исходный код]

Присоединяет к сервисам показатели вместимости из расчёта обеспеченности.

Существующие столбцы с теми же именами, что у показателей, удаляются и заменяются. Возвращаемый объект сохраняет тип и индекс входных данных.

Тип результата:

GeoDataFrame | DataFrame

Параметры:

Строит геометрию связей здание–сервис по ненулевым потокам.

Сервисы перепроецируются в систему координат зданий, если у обоих наборов задана система координат и они различаются. Для пустых потоков возвращается пустой GeoDataFrame. Связи, идентификаторов здания или сервиса которых нет в переданных GeoDataFrame, отбрасываются.

Тип результата:

GeoDataFrame

Параметры:
Показатель обеспеченности жилых зданий

Показатель обеспеченности жилых зданий школами из примера с порогом 10 минут по интермодальной матрице времени в пути (seed=0); точки — школы. Нежилые здания и улицы серые; чёрная линия — граница района.

Обеспеченность со связями здание–школа

Тот же результат с objectnat.get_provision_links(): по одной линии на ненулевой поток, ширина пропорциональна распределённому спросу. Тёмные связи лежат в пределах порога, светлые — за ним (до 3 * threshold); по светлым связям идёт спрос, который школы в пределах 10 минут не могут принять.

Пересчёт и обрезка

objectnat.recalculate_links() удаляет потоки со стоимостью больше new_max_dist и пересчитывает сводные показатели без нового распределения. Удалённый спрос не перераспределяется на другие сервисы; для полного перераспределения снова запустите objectnat.get_service_provision().

objectnat.clip_provision() оставляет здания, пересекающие selection_zone, связи этих зданий и сервисы, на которые ссылаются эти связи. Все четыре входных набора должны быть в одной системе координат.

Пересчитывает результат расчёта обеспеченности с меньшей максимальной стоимостью связи.

Потоки со стоимостью больше new_max_dist удаляются, а сводные показатели зданий и сервисов пересчитываются без перераспределения удалённого спроса.

Тип результата:

ProvisionResult

Параметры:
objectnat.clip_provision(buildings, services, links, selection_zone)[исходный код]

Обрезает результаты расчёта обеспеченности по заданной границе.

Оставляет только здания, пересекающие selection_zone, связи этих зданий и сервисы, на которые ссылаются эти связи.

Тип результата:

tuple[GeoDataFrame, GeoDataFrame, GeoDataFrame]

Параметры:
Обеспеченность после recalculate_links

recalculate_links(result, 10): связи длиннее 10 минут удалены, показатели пересчитаны; их спрос остаётся нераспределённым.

Обеспеченность, обрезанная по зоне отбора

objectnat.clip_provision() с кругом радиусом 450 м: здания в зоне, все их связи и школы, к которым ведут эти связи, в том числе школы за пределами зоны.

Ограничения

  • Распределение случайно: отдельные потоки зависят от seed; сводные показатели для больших наборов данных мало меняются от seed к seed, но для малых могут меняться.

  • Спрос и вместимость — целые числа (распределяются поштучно); дробные значения отбрасываются.

  • В модели нет явного поведения выбора (качество, предпочтения, правила закрепления); спрос может получить любой достижимый сервис в пределах 3 * threshold.

  • Результат точен настолько, насколько точна матрица стоимостей; матрица из примера содержит время в пути в минутах по интермодальному графу.

Примеры в ноутбуках

Матрица времени в пути от зданий до сервисов (матрица стоимостей с IduEdu) и Обеспеченность сервисами.