Выполнение выбора площадки с использованием Places Insights и BigQuery

Введение

В этом документе описывается, как создать решение для выбора места расположения путем объединения набора данных Places Insights , общедоступных геопространственных данных в BigQuery и API Place Details .

Он основан на демонстрации, представленной на конференции Google Cloud Next 2025, которую можно посмотреть на YouTube .

Карта Лас-Вегаса с потенциальными местами открытия новых кофеен, фиолетовым наложением данных и зелеными метками для существующих конкурентов.

Бизнес-вызов

Представьте, что вы владеете успешной сетью кофеен и хотите расширить своё присутствие в новом штате, например, в Неваде, где у вас ещё нет представительства. Открытие нового заведения — это серьёзная инвестиция, и принятие решения на основе данных критически важно для успеха. С чего же начать?

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

Рабочий процесс решения

Этот процесс следует логической воронке, начиная с общего и постепенно становясь более детальным, чтобы уточнить область поиска и повысить уверенность в окончательном выборе сайта.

Предпосылки и настройка среды

Прежде чем приступить к анализу, вам понадобится среда с несколькими ключевыми возможностями. В этом руководстве мы рассмотрим реализацию с использованием SQL и Python, но общие принципы можно применить и к другим технологическим стекам.

В качестве предварительного условия убедитесь, что ваша среда может:

Вам также необходимо визуализировать геопространственные данные на карте, что критически важно для интерпретации результатов каждого этапа анализа. Существует множество способов добиться этого. Вы можете использовать инструменты бизнес-аналитики, такие как Looker Studio , которые напрямую подключаются к BigQuery, или языки программирования для анализа данных, например, Python.

Анализ на уровне штата: найдите лучший округ

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

Наш запрос BigQuery достигает этого, используя встроенные компоненты адресов, доступные в наборе данных Places Insights. Запрос подсчитывает количество ресторанов, сначала фильтруя данные, чтобы включить только места в штате Невада, используя поле administrative_area_level_1_name . Затем он дополнительно уточняет этот набор, включая только места, где массив типов содержит « restaurant ». Наконец, он группирует эти результаты по названию округа ( administrative_area_level_2_name ), чтобы получить количество для каждого округа. Этот подход использует встроенную, предварительно проиндексированную структуру адресов набора данных.

В этом отрывке показано, как мы объединяем геометрию округов с Places Insights и фильтруем по определенному типу места — restaurant :

SELECT WITH AGGREGATION_THRESHOLD
  administrative_area_level_2_name,
  COUNT(*) AS restaurant_count
FROM
  `places_insights___us.places`
WHERE
  -- Filter for the state of Nevada
  administrative_area_level_1_name = 'Nevada'
  -- Filter for places that are restaurants
  AND 'restaurant' IN UNNEST(types)
  -- Filter for operational places only
  AND business_status = 'OPERATIONAL'
  -- Exclude rows where the county name is null
  AND administrative_area_level_2_name IS NOT NULL
GROUP BY
  administrative_area_level_2_name
ORDER BY
  restaurant_count DESC

Простого подсчёта количества ресторанов недостаточно; нам необходимо сопоставить его с данными о населении, чтобы получить истинное представление о насыщенности рынка и имеющихся возможностях. Мы будем использовать данные о населении из Бюро переписи населения США, посвящённые общей численности населения округов .

Чтобы сравнить эти две совершенно разные метрики (количество мест и численность населения), мы используем нормализацию по минимуму и максимуму. Этот метод масштабирует обе метрики до общего диапазона (от 0 до 1). Затем мы объединяем их в один normalized_score , присваивая каждой метрике 50%-ный вес для сбалансированного сравнения.

В этом фрагменте показана основная логика расчёта рейтинга. Она учитывает нормализованное население и количество ресторанов:

(
    -- Normalize restaurant count (scales to a 0-1 value) and apply 50% weight
    SAFE_DIVIDE(restaurant_count - min_restaurants, max_restaurants - min_restaurants) * 0.5
    +
    -- Normalize population (scales to a 0-1 value) and apply 50% weight
    SAFE_DIVIDE(population_2023 - min_pop, max_pop - min_pop) * 0.5
  ) AS normalized_score

После выполнения полного запроса возвращается список округов, количество ресторанов, численность населения и нормализованный балл. Сортировка по normalized_score DESC показывает, что округ Кларк является явным победителем для дальнейшего исследования и главным претендентом.

Таблица результатов поиска, в которой перечислены 4 лучших округа Невады, где округ Кларк занял первое место с нормализованным баллом 1,0.

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

Анализ на уровне округа: найдите самые загруженные коммерческие зоны

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

Этот запрос использует таблицу brands в Places Insights, содержащую информацию о конкретных брендах. К этой таблице можно обратиться, чтобы получить список поддерживаемых брендов. Сначала мы определяем список наших целевых брендов, а затем объединяем его с основным набором данных Places Insights, чтобы подсчитать, сколько таких магазинов приходится на каждый почтовый индекс в округе Кларк.

Наиболее эффективный способ достижения этой цели — двухэтапный подход:

  1. Сначала мы выполним быстрое негеопространственное агрегирование для подсчета брендов в пределах каждого почтового индекса.
  2. Во-вторых, мы присоединим эти результаты к общедоступному набору данных , чтобы получить границы карты для визуализации.

Подсчитайте бренды, используя поле postal_code_names

Этот первый запрос реализует основную логику подсчёта. Он фильтрует населённые пункты округа Кларк, а затем извлекает массив postal_code_names для группировки количества брендов по почтовому индексу.

WITH brand_names AS (
  -- First, select the chains we are interested in by name
  SELECT
    id,
    name
  FROM
    `places_insights___us.brands`
  WHERE
    name IN ('7-Eleven', 'CVS', 'Walgreens', 'Subway Restaurants', "McDonald's")
)
SELECT WITH AGGREGATION_THRESHOLD
  postal_code,
  COUNT(*) AS total_brand_count
FROM
  `places_insights___us.places` AS places_table,
  -- Unnest the built-in postal code and brand ID arrays
  UNNEST(places_table.postal_code_names) AS postal_code,
  UNNEST(places_table.brand_ids) AS brand_id
JOIN
  brand_names
  ON brand_names.id = brand_id
WHERE
  -- Filter directly on the administrative area fields in the places table
  places_table.administrative_area_level_2_name = 'Clark County'
  AND places_table.administrative_area_level_1_name = 'Nevada'
GROUP BY
  postal_code
ORDER BY
  total_brand_count DESC

На выходе получается таблица почтовых индексов и соответствующего им количества брендов.

Таблица результатов запроса с перечнем почтовых индексов и общего количества брендов, при этом у 89119 максимальное количество — 38.

Прикрепите геометрию почтового индекса для отображения на карте

Теперь, когда у нас есть данные о количестве, мы можем получить формы многоугольников, необходимые для визуализации. Этот второй запрос берёт наш первый запрос, оборачивает его в общее табличное выражение (CTE) с именем brand_counts_by_zip и объединяет его результаты с общедоступной geo_us_boundaries.zip_codes table . Это эффективно привязывает геометрию к нашим предварительно рассчитанным данным.

WITH brand_counts_by_zip AS (
  -- This will be the entire query from the previous step, without the final ORDER BY (excluded for brevity).
  . . .
)
-- Now, join the aggregated results to the boundaries table
SELECT
  counts.postal_code,
  counts.total_brand_count,
  -- Simplify the geometry for faster rendering in maps
  ST_SIMPLIFY(zip_boundaries.zip_code_geom, 100) AS geography
FROM
  brand_counts_by_zip AS counts
JOIN
  `bigquery-public-data.geo_us_boundaries.zip_codes` AS zip_boundaries
  ON counts.postal_code = zip_boundaries.zip_code
ORDER BY
  counts.total_brand_count DESC

На выходе получается таблица почтовых индексов, соответствующих им количеств брендов и геометрии почтового индекса.

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

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

Тепловая карта Лас-Вегаса, показывающая наибольшую концентрацию целевых брендов красным и жёлтым цветом.

Гиперлокальный анализ: оценка отдельных областей сетки

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

Наш следующий запрос становится по-настоящему конкретным. Он начинается с создания мелкозернистой гексагональной сетки для агломерации Лас-Вегаса с использованием стандартного геопространственного индекса H3 (с разрешением 8) для анализа территории на микроуровне. Сначала запрос определяет все сопутствующие компании, работающие в пиковое время (понедельник, с 10:00 до 14:00).

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

В этом отрывке описывается логика взвешенной оценки, которая ссылается на предварительно рассчитанный флаг ( is_open_monday_window ) для проверки часов работы:

. . .
(
  COUNTIF('restaurant' IN UNNEST(types) AND is_open_monday_window) * 8 +
  COUNTIF('convenience_store' IN UNNEST(types) AND is_open_monday_window) * 3 +
  COUNTIF('bar' IN UNNEST(types) AND is_open_monday_window) * 7 +
  COUNTIF('tourist_attraction' IN UNNEST(types) AND is_open_monday_window) * 6 +
  COUNTIF('casino' IN UNNEST(types) AND is_open_monday_window) * 7
) AS suitability_score
. . .

Развернуть для полного запроса

    -- This query calculates a custom 'suitability score' for different areas in the Las Vegas
-- metropolitan area to identify prime commercial zones. It uses a weighted model based
-- on the density of specific business types that are open during a target time window.

-- Step 1: Pre-filter the dataset to only include relevant places.
-- This CTE finds all places in our target localities (Las Vegas, Spring Valley, etc.) and
-- adds a boolean flag 'is_open_monday_window' for those open during the target time.
WITH PlacesInTargetAreaWithOpenFlag AS (
  SELECT
    point,
    types,
    EXISTS(
      SELECT 1
      FROM UNNEST(regular_opening_hours.monday) AS monday_hours
      WHERE
        monday_hours.start_time <= TIME '10:00:00'
        AND monday_hours.end_time >= TIME '14:00:00'
    ) AS is_open_monday_window
  FROM
    `places_insights___us.places`
  WHERE
    EXISTS (
        SELECT 1 FROM UNNEST(locality_names) AS locality
        WHERE locality IN ('Las Vegas', 'Spring Valley', 'Paradise', 'North Las Vegas', 'Winchester')
    )
    AND administrative_area_level_1_name = 'Nevada'
),
-- Step 2: Aggregate the filtered places into H3 cells and calculate the suitability score.
-- Each place's location is converted to an H3 index (at resolution 8). The query then
-- calculates a weighted 'suitability_score' and individual counts for each business type
-- within that cell.
TileScores AS (
  SELECT WITH AGGREGATION_THRESHOLD
    -- Convert each place's geographic point into an H3 cell index.
    `carto-os.carto.H3_FROMGEOGPOINT`(point, 8) AS h3_index,

    -- Calculate the weighted score based on the count of places of each type
    -- that are open during the target window.
    (
      COUNTIF('restaurant' IN UNNEST(types) AND is_open_monday_window) * 8 +
      COUNTIF('convenience_store' IN UNNEST(types) AND is_open_monday_window) * 3 +
      COUNTIF('bar' IN UNNEST(types) AND is_open_monday_window) * 7 +
      COUNTIF('tourist_attraction' IN UNNEST(types) AND is_open_monday_window) * 6 +
      COUNTIF('casino' IN UNNEST(types) AND is_open_monday_window) * 7
    ) AS suitability_score,

    -- Also return the individual counts for each category for detailed analysis.
    COUNTIF('restaurant' IN UNNEST(types) AND is_open_monday_window) AS restaurant_count,
    COUNTIF('convenience_store' IN UNNEST(types) AND is_open_monday_window) AS convenience_store_count,
    COUNTIF('bar' IN UNNEST(types) AND is_open_monday_window) AS bar_count,
    COUNTIF('tourist_attraction' IN UNNEST(types) AND is_open_monday_window) AS tourist_attraction_count,
    COUNTIF('casino' IN UNNEST(types) AND is_open_monday_window) AS casino_count
  FROM
    -- CHANGED: This now references the CTE with the expanded area.
    PlacesInTargetAreaWithOpenFlag
  -- Group by the H3 index to ensure all calculations are per-cell.
  GROUP BY
    h3_index
),
-- Step 3: Find the maximum suitability score across all cells.
-- This value is used in the next step to normalize the scores to a consistent scale (e.g., 0-10).
MaxScore AS (
  SELECT MAX(suitability_score) AS max_score FROM TileScores
)
-- Step 4: Assemble the final results.
-- This joins the scored tiles with the max score, calculates the normalized score,
-- generates the H3 cell's polygon geometry for mapping, and orders the results.
SELECT
  ts.h3_index,
  -- Generate the hexagonal polygon for the H3 cell for visualization.
  `carto-os.carto.H3_BOUNDARY`(ts.h3_index) AS h3_geography,
  ts.restaurant_count,
  ts.convenience_store_count,
  ts.bar_count,
  ts.tourist_attraction_count,
  ts.casino_count,
  ts.suitability_score,
  -- Normalize the score to a 0-10 scale for easier interpretation.
  ROUND(
    CASE
      WHEN ms.max_score = 0 THEN 0
      ELSE (ts.suitability_score / ms.max_score) * 10
    END,
    2
  ) AS normalized_suitability_score
FROM
  -- A cross join is efficient here as MaxScore contains only one row.
  TileScores ts, MaxScore ms
-- Display the highest-scoring locations first.
ORDER BY
  normalized_suitability_score DESC;
    

Визуализация этих результатов на карте показывает очевидные выигрышные локации. Самые тёмно-фиолетовые участки, в основном рядом с Лас-Вегас-Стрип и центром города, — это районы с наибольшим потенциалом для строительства нашей новой кофейни.

Карта-карта Лас-Вегаса, на которой для отображения оценок пригодности используется фиолетовая шестиугольная сетка, а более темные оттенки указывают на более высокий потенциал.

Анализ конкурентов: определение существующих кофеен

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

Для этого мы используем функцию PLACES_COUNT_PER_H3 . Эта функция предназначена для эффективного подсчёта количества мест в указанной географической области по ячейке H3.

Сначала мы динамически определяем географию всей агломерации Лас-Вегаса. Вместо того, чтобы полагаться на отдельный населённый пункт, мы запрашиваем общедоступный набор данных Overture Maps, чтобы получить границы Лас-Вегаса и его основных прилегающих населённых пунктов, объединяя их в один полигон с помощью ST_UNION_AGG . Затем мы передаём эту область в функцию, прося её подсчитать все действующие кофейни.

Этот запрос определяет агломерацию и вызывает функцию для получения количества кофеен в ячейках H3:

-- Define a variable to hold the combined geography for the Las Vegas metro area.
DECLARE las_vegas_metro_area GEOGRAPHY;

-- Set the variable by fetching the shapes for the five localities from Overture Maps
-- and merging them into a single polygon using ST_UNION_AGG.
SET las_vegas_metro_area = (
  SELECT
    ST_UNION_AGG(geometry)
  FROM
    `bigquery-public-data.overture_maps.division_area`
  WHERE
    country = 'US'
    AND region = 'US-NV'
    AND names.primary IN ('Las Vegas', 'Spring Valley', 'Paradise', 'North Las Vegas', 'Winchester')
);

-- Call the PLACES_COUNT_PER_H3 function with our defined area and parameters.
SELECT
  *
FROM
  `places_insights___us.PLACES_COUNT_PER_H3`(
    JSON_OBJECT(
      -- Use the metro area geography we just created.
      'geography', las_vegas_metro_area,
      -- Specify 'coffee_shop' as the place type to count.
      'types', ["coffee_shop"],
      -- Best practice: Only count places that are currently operational.
      'business_status', ['OPERATIONAL'],
      -- Set the H3 grid resolution to 8.
      'h3_resolution', 8
    )
  );

Функция возвращает таблицу, которая включает индекс ячейки H3, ее геометрию, общее количество кофеен и выборку их идентификаторов мест:

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

Хотя агрегированные данные полезны, важно видеть реальных конкурентов. Именно здесь мы переходим от набора данных Places Insights к API Places . Извлекая идентификаторы sample_place_ids из ячеек с наивысшим нормализованным рейтингом пригодности, мы можем вызвать API Place Details для получения подробной информации о каждом конкуренте, такой как его имя, адрес, рейтинг и местоположение.

Для этого необходимо сравнить результаты предыдущего запроса, в котором был сгенерирован показатель пригодности, и запроса PLACES_COUNT_PER_H3 . Индекс ячеек H3 можно использовать для получения количества кофеен и их идентификаторов из ячеек с наивысшим нормализованным показателем пригодности.

Этот код Python демонстрирует, как можно выполнить такое сравнение.

    # Isolate the Top 5 Most Suitable H3 Cells
    top_suitability_cells = gdf_suitability.head(5)

    # Extract the 'h3_index' values from these top 5 cells into a list.
    top_h3_indexes = top_suitability_cells['h3_index'].tolist()
    print(f"The top 5 H3 indexes are: {top_h3_indexes}")

    # Now, we find the rows in our DataFrame where the
    # 'h3_cell_index' matches one of the indexes from our top 5 list.

    coffee_counts_in_top_zones = gdf_coffee_shops[
        gdf_coffee_shops['h3_cell_index'].isin(top_h3_indexes)
    ]

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

Это можно сделать, отправив запрос к API Place Details напрямую для каждого идентификатора места или используя клиентскую библиотеку . Не забудьте установить параметр FieldMask , чтобы запрашивать только необходимые данные.

Наконец, мы объединяем всё в единую, мощную визуализацию. Мы используем нашу фиолетовую карту пригодности в качестве базового слоя, а затем добавляем метки для каждой отдельной кофейни, полученные из API Places. Эта итоговая карта представляет собой наглядное представление, синтезирующее весь наш анализ: тёмно-фиолетовые области отображают потенциал, а зелёные метки — текущее состояние рынка.

Карта Лас-Вегаса с фиолетовой шестиугольной сеткой, показывающей перспективные зоны, и зелёными метками, обозначающими существующие кофейни.

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

Карта крупным планом двух перспективных фиолетовых районов Лас-Вегаса, показывающая расположение конкурентов и явные пробелы на рынке.

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

Заключение

В этом документе мы перешли от вопроса масштаба штата « куда расширяться?» к локальному ответу, подкрепленному данными. Наложение различных наборов данных и применение настраиваемой бизнес-логики позволяет систематически снижать риски, связанные с принятием важных бизнес-решений. Этот рабочий процесс, сочетающий в себе масштаб BigQuery, богатый функционал Places Insights и детализацию данных API Places в режиме реального времени, представляет собой мощный шаблон для любой организации, стремящейся использовать данные о местоположении для стратегического роста.

Следующие шаги

  • Адаптируйте этот рабочий процесс с учетом вашей собственной бизнес-логики, целевых географических регионов и собственных наборов данных.
  • Изучите другие поля данных в наборе данных Places Insights, такие как количество отзывов, уровни цен и оценки пользователей, чтобы еще больше обогатить свою модель.
  • Автоматизируйте этот процесс, чтобы создать внутреннюю панель выбора площадок, которую можно использовать для динамической оценки новых рынков.

Подробнее в документации:

Авторы

Хенрик Валв | Инженер DevX