利用地点数据洞见创建自定义位置得分

概览

一则房地产房源信息,其中显示了基于附近公园和宠物友好场所的自定义宠物主人天堂得分 9.1。

标准位置信息数据可以告诉您附近什么,但通常无法回答更重要的问题:“这个区域对我来说怎么样?”用户的需求是细致入微的。与养狗的年轻专业人士相比,有幼儿的家庭有不同的优先事项。为了帮助他们做出有把握的决策,您需要提供反映这些特定需求的分析洞见。自定义位置得分是一项强大的工具,可帮助您实现这一价值,并打造显著差异化的用户体验。

本文档介绍了如何使用 BigQuery 中的 Places Insights 数据集创建自定义的多方面位置得分。通过将 POI 数据转换为有意义的指标,您可以丰富房地产、零售或旅游应用,并为用户提供所需的相关信息。我们还提供了一个选项,让您可以使用 Gemini Developer API 来计算位置得分,这是一种强大的方法。

通过量身定制的分数提升业务价值

以下示例说明了如何将原始位置数据转换为以用户为中心的强大指标,从而改进您的应用。

  • 房地产开发商可以创建“家庭友好度得分”或“通勤者理想度得分”,帮助买家和租客选择符合其生活方式的理想社区,从而提高用户互动度、增加优质潜在客户并加快转化速度。
  • 旅游和酒店行业的工程师可以构建“夜生活指数”或“观光天堂指数”,帮助旅客选择符合其度假风格的酒店,从而提高预订率和客户满意度
  • 零售分析师可以生成“健身与健康指数”,根据附近的互补型商家确定新健身房或健康食品店的最佳位置,从而最大限度地提高定位合适用户群体的潜力。

在本指南中,您将学习一种灵活的三部分方法,用于直接在 BigQuery 中使用 Places 数据构建任何类型的自定义位置得分。我们将通过构建两个不同的示例得分来演示此模式:家庭友好度得分宠物主人天堂得分。借助此方法,您可以超越地点数量的限制,充分利用 Places Insights 数据集中的丰富详细属性。您可以利用营业时间、地点是否适合儿童或是否允许携带狗狗等信息,为用户创建精细而有意义的指标。

解决方案工作流

一个三步工作流程图:确定位置、查询附近地点,以及对结果进行归一化处理以创建最终得分。

本教程使用一个强大的 SQL 查询来构建自定义得分,您可以根据任何使用情形调整该得分。我们将通过为一组假设的公寓房源构建两个示例得分来演示此流程。

前提条件

在开始之前,请按照这些说明设置地点分析。

1. 建立基础:您感兴趣的地点

在创建得分之前,您需要一份要分析的营业地点列表。第一步是确保此数据以表的形式存在于 BigQuery 中。关键在于为每个位置提供一个唯一标识符,并提供一个用于存储其坐标的 GEOGRAPHY 列。

您可以使用如下查询创建并填充要评分的位置表:

CREATE OR REPLACE TABLE `your_project.your_dataset.apartment_listings`
(
  id INT64,
  name STRING,
  location GEOGRAPHY
);

INSERT INTO `your_project.your_dataset.apartment_listings` VALUES
  (1, 'The Downtowner', ST_GEOGPOINT(-74.0077, 40.7093)),
  (2, 'Suburban Oasis', ST_GEOGPOINT(-73.9825, 40.7507)),
  (3, 'Riverside Lofts', ST_GEOGPOINT(-73.9470, 40.8079))
  -- More rows can be added here
  . . . ;

对位置数据执行 SELECT * 的效果如下所示。

BigQuery 查询结果,显示包含 ID、名称和位置坐标的公寓房源表格。

2. 开发核心逻辑:评分查询

确定位置后,下一步是查找、过滤和统计与自定义得分相关的附近地点。所有这些操作都可以在单个 SELECT 语句中完成。

使用地理空间搜索功能查找附近地点

首先,您需要从“地点概览”数据集中找到距离每个营业地点一定距离内的所有地点。BigQuery 函数 ST_DWITHIN 非常适合此用途。我们将对 apartment_listings 表和 places_insights 表执行 JOIN,以查找半径 800 米内的所有地点。LEFT JOIN 可确保搜索结果中包含您的所有原始位置,即使附近没有找到匹配的地点也是如此。

使用高级属性过滤相关性

您可以在此处将得分的抽象概念转化为具体的数据过滤条件。对于我们的两个示例得分,相应标准有所不同:

  • 对于“亲子友好度得分”,我们关注的是明确适合儿童的公园、博物馆和餐厅。
  • 对于“宠物主人天堂指数”,我们会考虑公园、兽医诊所、宠物店以及允许携带狗狗进入的任何餐厅或咖啡馆。

您可以在查询的 WHERE 子句中直接过滤这些特定属性。

汇总每个位置的洞见

最后,您需要统计每个公寓附近有多少个相关地点。GROUP BY 子句用于汇总结果,而 COUNTIF 函数用于统计符合每种得分的特定条件的地点数量。

以下查询将这三个步骤结合在一起,只需一次遍历即可计算出两个得分的原始计数:

-- This Common Table Expression (CTE) will hold the raw counts for each score component.
WITH insight_counts AS (
  SELECT WITH AGGREGATION_THRESHOLD -- Correctly includes the mandatory aggregation threshold
    apartments.id,
    apartments.name,
    COUNTIF(places.primary_type = 'park') AS park_count,
    COUNTIF(places.primary_type = 'museum') AS museum_count,
    COUNTIF(places.primary_type = 'restaurant' AND places.good_for_children = TRUE) AS family_restaurant_count,
    COUNTIF(places.primary_type IN ('veterinary_care', 'pet_store')) AS pet_service_count,
    COUNTIF(places.allows_dogs = TRUE) AS dog_friendly_place_count
  FROM
    `your_project.your_dataset.apartment_listings` AS apartments
  LEFT JOIN
    `your-project.places_insights___us.places` AS places -- Corrected table name for the US dataset
    ON ST_DWITHIN(apartments.location, places.point, 800) -- Find places within 800 meters
  GROUP BY
    apartments.id, apartments.name
)
SELECT * FROM insight_counts;

此查询的结果将类似于以下内容。

BigQuery 结果,显示了每个公寓房源的公园、餐厅和宠物服务等便利设施的原始数量。

我们将在下一部分中基于这些结果进行构建。

3. 创建得分

现在,您已经获得了每个位置的地点数量和每种地点类型的权重,接下来就可以生成自定义位置得分了。本部分将讨论两种方案:在 BigQuery 中使用您自己的自定义计算,或使用 Gemini Developer API

方法 1:在 BigQuery 中使用您自己的自定义计算

上一步骤中的原始计数很有参考价值,但我们的目标是获得一个简单易懂的分数。最后一步是使用权重组合这些数量,然后将结果归一化到 0-10 的范围内。

应用自定义权重:选择权重既是艺术,也是科学。 它们需要反映您的业务优先级或您认为对用户最重要的内容。对于“适合家庭”得分,您可能会认为公园的重要性是博物馆的两倍。先从最佳假设入手,然后根据用户反馈进行迭代。

对得分进行归一化处理 下面的查询使用了两个通用表表达式 (CTE):第一个 CTE 用于计算原始计数(与之前一样),第二个 CTE 用于计算加权得分。最后的 SELECT 语句会对加权分数执行最小-最大归一化。输出示例 apartment_listings 表的 location 列,以在地图上实现数据可视化。

WITH
  -- CTE 1: Count nearby amenities of interest for each apartment listing.
  insight_counts AS (
    SELECT WITH AGGREGATION_THRESHOLD
      apartments.id,
      apartments.name,
      COUNTIF(places.primary_type = 'park') AS park_count,
      COUNTIF(places.primary_type = 'museum') AS museum_count,
      COUNTIF(places.primary_type = 'restaurant' AND places.good_for_children = TRUE) AS family_restaurant_count,
      COUNTIF(places.primary_type IN ('veterinary_care', 'pet_store')) AS pet_service_count,
      COUNTIF(places.allows_dogs = TRUE) AS dog_friendly_place_count
    FROM
      `your_project.your_dataset.apartment_listings` AS apartments
    LEFT JOIN
      `your-project.places_insights___us.places` AS places
      ON ST_DWITHIN(apartments.location, places.point, 800)
    GROUP BY
      apartments.id,
      apartments.name
  ),
  -- CTE 2: Apply custom weighting to the amenity counts to generate raw scores.
  raw_scores AS (
    SELECT
      id,
      name,
      (park_count * 3.0) + (museum_count * 1.5) + (family_restaurant_count * 2.5) AS family_friendliness_score,
      (park_count * 2.0) + (pet_service_count * 3.5) + (dog_friendly_place_count * 2.5) AS pet_paradise_score
    FROM
      insight_counts
  )
-- Final Step: Normalize scores to a 0-10 scale and rejoin to retrieve the location geometry.
SELECT
  raw_scores.id,
  raw_scores.name,
  apartments.location,
  raw_scores.family_friendliness_score,
  raw_scores.pet_paradise_score,
  -- Normalize Family Score using a MIN/MAX window function.
  ROUND(
    COALESCE(
      SAFE_DIVIDE(
        (raw_scores.family_friendliness_score - MIN(raw_scores.family_friendliness_score) OVER ()),
        (MAX(raw_scores.family_friendliness_score) OVER () - MIN(raw_scores.family_friendliness_score) OVER ())
      ) * 10,
      0
    ),
    2
  ) AS normalized_family_score,
  -- Normalize Pet Score using a MIN/MAX window function.
  ROUND(
    COALESCE(
      SAFE_DIVIDE(
        (raw_scores.pet_paradise_score - MIN(raw_scores.pet_paradise_score) OVER ()),
        (MAX(raw_scores.pet_paradise_score) OVER () - MIN(raw_scores.pet_paradise_score) OVER ())
      ) * 10,
      0
    ),
    2
  ) AS normalized_pet_score
FROM
  raw_scores
JOIN
  `your_project.your_dataset.apartment_listings` AS apartments
  ON raw_scores.id = apartments.id;

查询结果将类似于以下内容。最后两列是归一化得分。

最终查询结果,显示每个公寓房源的原始加权得分和归一化后的 0-10 分。

了解标准化得分

请务必了解此最终归一化步骤为何如此重要。原始加权得分的范围为 0 到一个可能非常大的数字,具体取决于您所在位置的城市密度。对于没有上下文的用户来说,500 分毫无意义。

归一化会将这些抽象数字转换为相对排名。通过将结果缩放到 0 到 10 之间,该得分可清晰地传达每个位置与特定数据集中的其他位置相比如何:

  • 系统会为原始得分最高的地点分配 10 分,将其标记为当前组中的最佳选项。
  • 原始得分最低的位置会被分配 0 分,作为比较基准。这并不意味着该位置没有任何便利设施,而是相对于正在评估的其他选项而言,该位置最不适合。
  • 所有其他得分都按比例介于两者之间,让用户能够一目了然地比较各种选项。

方法 2:使用 Gemini Developer API

除了在 BigQuery 中使用固定的数学公式之外,Gemini Developer API 还提供了一种强大的方式来计算细致的自定义位置得分。

虽然选项 1 非常适合根据便利设施数量进行纯粹的定量评分,但它无法轻松纳入定性数据。借助 Gemini,您可以将 Places Insights 查询中的数字与非结构化数据(例如公寓房源的文字说明)相结合,“此位置适合家庭入住,夜间安静”)或特定用户个人资料偏好设置(例如,“此用户为家人预订,偏好位于中心位置的安静区域”),以生成更细致的得分。

为 Gemini 准备数据

如需使用此方法,请将 BigQuery 汇总的结果(来自第 2 步)转换为 Markdown 格式,并将其与定性数据(例如 Listing Description)相结合。

在此示例中,我们有两个特征截然不同的房源。我们还添加了 Target User Profile,以便让 Gemini 知道我们正在为谁评分:

## Listing 1: The Downtowner

*   **ID:** 1
*   **Amenity Counts:**
    *   Parks: 70
    *   Museums: 34
    *   Family-Friendly Restaurants: 141
*   **Listing Description:** A vibrant apartment in the heart of the city.
    Great for nightlife, but can be noisy on weekends. Close to several
    small playgrounds.
*   **Target User Profile:** Young family with a toddler, looking for a
    balance of activity and quiet.

---

## Listing 2: Suburban Oasis

*   **ID:** 2
*   **Amenity Counts:**
    *   Parks: 34
    *   Museums: 30
    *   Family-Friendly Restaurants: 318
*   **Listing Description:** Quiet, tree-lined street. Large backyard and easy
    walking distance to a major park and elementary school.
*   **Target User Profile:** Young family with a toddler, looking for a
    balance of activity and quiet.
系统指令

Gemini 需要系统指令才能了解如何权衡这些不同的数据点。您可以明确告知模型特定便利设施的重要性,同时指示模型将文本描述的情感纳入考虑范围。

You are an expert real estate analyst. Your goal is to generate a
"Family-Friendliness Score" between 0.0 and 10.0 for a list of apartment
locations.

For each location, you will be given quantitative data (amenity counts)
and qualitative data (descriptions and user profiles).

Scoring Criteria:
-   High importance: Proximity to parks and a high count of family-friendly
    restaurants.
-   Medium importance: Proximity to museums.
-   Negative modifiers: Descriptions indicating excessive noise, lack of
    safe play areas, or mismatch with the user profile.
-   Positive modifiers: Descriptions indicating quiet areas, safe streets,
    or extra space (e.g., backyards).

Analyze the provided data and generate scores based on these criteria.
结构化输出

为确保将 AI 集成到应用中时的可靠性,您不应仅依赖提示来确定输出格式。请改用 Gemini 的结构化输出功能。通过提供 responseSchema,您可以确保模型返回一个干净、可解析的 JSON 数组,该数组完全符合您的系统要求。

在我们的示例中,我们可以强制执行以下架构:

{
  "type": "ARRAY",
  "items": {
    "type": "OBJECT",
    "required": ["location_id", "name", "score", "reasoning"],
    "properties": {
      "location_id": {"type": "STRING"},
      "name": {"type": "STRING"},
      "score": {
        "type": "NUMBER"
      },
      "reasoning": {
        "type": "STRING"
      }
    }
  }
}
输出示例

当您发送包含已定义的 responseSchema 的提示时,Gemini 会返回一个结构化的 JSON 数组,可供您的应用直接使用。

请注意,在输出中,Gemini 如何处理权衡取舍。“The Downtowner”的公园数量非常多,但 Gemini 认为“周末很吵”的描述对幼儿来说是一个主要缺点。与此同时,“郊区绿洲”将出色的设施密度与适用的定性特征(例如“安静的绿树成荫的街道”)相结合,获得了近乎完美的得分。

[
  {
    "id": 1,
    "location_name": "The Downtowner",
    "analysis_notes": "Excellent amenity counts (parks, restaurants, museums), fulfilling
    quantitative metrics. However, the qualitative data indicates excessive weekend
    noise and a strong nightlife focus, conflicting directly with the target
    user's need for quiet and suitability for a toddler. This mismatch
    significantly lowers the final score.",
    "family_friendliness_score": 5.5
  },
  {
    "id": 2,
    "location_name": "Suburban Oasis",
    "analysis_notes": "Outstanding quantitative data, especially the very high count of
    family-friendly restaurants. The qualitative description (quiet, tree-lined street,
    large backyard, proximity to elementary school and major park) aligns perfectly with
    and exceeds the needs of the target family profile. High positive modifiers
    result in a near-perfect score.",
    "family_friendliness_score": 9.8
  }
]

此方法可让您提供高度个性化的评分,让每位用户都能理解并感觉是为自己量身定制的。

4. 在地图上直观呈现您的得分

对于包含 GEOGRAPHY 列的任何查询结果,BigQuery Studio 都包含集成式地图可视化图表。由于我们的查询会输出 location 列,因此您可以立即直观呈现得分。

点击 Visualization 标签页会显示地图,而 Data Column 下拉菜单用于控制要直观呈现的地理位置得分。在此示例中,normalized_pet_score 是从示例 1 中直观呈现的。请注意,在此示例中,apartment_listings 表中添加了更多位置。

一张地图,直观呈现了各个位置的归一化宠物得分,其中深绿色圆点表示得分较高,更有利于宠物。

直观呈现数据后,您便可一目了然地了解所创建得分的最合适位置,其中深绿色圆圈表示 normalized_pet_score 较高的位置(在本例中)。如需了解更多地点数据分析数据可视化选项,请参阅直观呈现查询结果

总结

现在,您已掌握一种强大且可重复使用的方法,可用于创建细致的地理位置得分。您从自己的位置信息入手,在 BigQuery 中构建了一个 SQL 查询,用于查找附近具有 ST_DWITHIN 的地点,按 good_for_childrenallows_dogs 等高级属性过滤这些地点,并使用 COUNTIF 汇总结果。通过应用自定义权重并对结果进行归一化处理,您生成了一个简单易懂的分数,可提供深入且可据以采取行动的分析洞见。您可以直接应用此模式,将原始位置数据转化为显著的竞争优势。

后续操作

现在,轮到您大显身手了。本教程提供了一个模板。您可以使用 Places Insights 架构中提供的丰富数据来创建最符合您的使用情形的分数。您可以考虑构建以下其他得分:

  • “夜生活指数”:结合 primary_typebarnight_club)、price_level 和深夜营业时间过滤条件,找到夜幕降临后最热闹的地区。
  • “健康与健身得分”:统计附近的 gymsparkshealth_food_stores,并过滤出提供 serves_vegetarian_food 的餐厅,以便为注重健康的用户提供位置得分。
  • “通勤族理想之地”得分:查找附近有大量 transit_stationparking 地点的位置,以帮助重视交通便利性的用户。

贡献者

Henrik Valve | DevX 工程师