Places Insights と BigQuery ML を使用してサイトのパフォーマンスを分析する

イメージ

スタッフ、在庫、運用方法が同じなのに、あるサイトは成功し、別のサイトはパフォーマンスが低いのはなぜですか?複数の店舗を持つ企業は、ポートフォリオ全体のパフォーマンスのばらつきを説明するのに苦労することがよくあります。答えは通常、外部環境に隠されています。スポット(POI)データを活用することで、経験則に基づく説明を超えて、地域の競合店の密度や近隣地域の特性がサイトの成功にどのように影響するかを正確に定量化できます。

このガイドでは、Places InsightsBigQuery ML を使用して、周辺環境がサイトの成功に与える影響を定量化する方法について説明します。独自のサイト パフォーマンス データと外部の地理空間シグナルを組み合わせて、パフォーマンスの要因を診断します。

ロンドンのサイトのデータセットを使用して、線形回帰モデルを構築します。このワークフローでは H3 空間インデックスを使用します。このシステムは、都市を均一な六角形のセルに分割します。環境データをこれらのセルに集約することで、既存のサイトだけでなく、市内のあらゆる地域のパフォーマンスの可能性を予測するモデルをトレーニングできます。

学習内容は次のとおりです。

  1. 特徴をエンジニアリングする: サイトから半径 500 メートル以内のジム、学校、交通機関の駅などの地図上の場所(POI)の数を集計します。
  2. モデルをトレーニングする: BigQuery ML を使用して、これらの環境の特徴と内部パフォーマンス指標を関連付ける回帰モデルを構築します。
  3. 都市のスコア付け: トレーニング済みのモデルをロンドンの H3 グリッド全体に適用して、将来の拡大の可能性が高いホットスポットを特定します。

BigQuery ML を初めて使用する場合は、BigQuery ML の概要で、コアコンセプトとサポートされているモデルタイプを確認してください。

イメージ

インタラクティブ環境でこのワークフローを試すには、次のノートブックを実行します。このチュートリアルでは、BigQuery ML で予測モデルを構築し、H3 空間インデックスを使用して都市全体の機会を可視化する方法について説明します。

前提条件

始める前に、次の準備をしてください。

  • Google Cloud プロジェクト:

    • 課金を有効にした Google Cloud プロジェクト
  • データアクセス:

  • Google Maps Platform:

  • Python 環境とライブラリ:

    • Google Cloud コンソールの Colab Enterprise などの Python 環境。
    • 次のライブラリがインストールされている。
      ライブラリ 説明
      pandas-gbq BigQuery の操作。
      geopandas 地理空間データ オペレーションの処理。
      folium インタラクティブな地図を作成します。
      shapely 幾何学的操作。
  • IAM 権限:

    • ユーザー アカウントまたはサービス アカウントに次の IAM ロールがあることを確認します。
      ロール ID
      BigQuery データ編集者 roles/bigquery.dataEditor
      BigQuery ユーザー roles/bigquery.user
  • 費用意識:

    • このチュートリアルでは、課金対象となる Google Cloud コンポーネントを使用します。次の項目に関連する費用が発生する可能性があることに注意してください。
      • BigQuery ML: 使用されたコンピューティング スロットに対して課金されます。BigQuery ML の料金をご覧ください。
      • Places Insights: クエリの使用量に基づいて課金されます。

Places Insights を使用した特徴量エンジニアリング

サイトのパフォーマンスを左右する外部要因を特定するには、未加工の POI データを定量化可能な特徴に変換する必要があります。各サイトから半径 500 メートル以内のジム、学校、交通機関の駅などの特定の施設や場所の密度を計算します。選択するアメニティは、ビジネスに最も関連性が高いと思われるものによって異なります。

イメージ

このステップでは、Python と pandas-gbq ライブラリを使用します。この方法を使用すると、Places Insights データセットへのアクセスに必要な SELECT WITH AGGREGATION_THRESHOLD クエリを実行し、結果をプロジェクトの新しいテーブルに保存できます。Places Insights データの操作について詳しくは、データセットを直接クエリするをご覧ください。

特徴量エンジニアリング クエリを実行する

環境(Colab Enterprise など)で次の Python スクリプトを実行します。このスクリプトは、内部サイトのデータを Places Insights データセットに接続します。

from google.cloud import bigquery
import pandas_gbq

# Configuration
project_id = 'your_project_id'
dataset_id = 'your_dataset_id'
features_table_id = f'{dataset_id}.site_features'

client = bigquery.Client(project=project_id)

# Define the Feature Engineering Query
# We count specific amenities within 500m of each site in London.
sql = f"""
SELECT WITH AGGREGATION_THRESHOLD
    internal.store_id,
    internal.store_performance,

    -- Feature Engineering: count nearby POIs by type
    COUNTIF('gym' IN UNNEST(places.types)) AS gym_count,
    COUNTIF('restaurant' IN UNNEST(places.types)) AS restaurant_count,
    COUNTIF('school' IN UNNEST(places.types)) AS school_count,
    COUNTIF('transit_station' IN UNNEST(places.types)) AS transit_count,
    COUNTIF('clothing_store' IN UNNEST(places.types)) AS clothing_store_count

FROM
    `{dataset_id}.site_performance` AS internal
JOIN
    `places_insights___gb.places` AS places
    ON ST_DWITHIN(internal.location, places.point, 500)
WHERE
    places.business_status = 'OPERATIONAL'
GROUP BY
    internal.store_id, internal.store_performance
"""

print("1. Running Feature Engineering Query...")

# Execute the query and download results to a Pandas DataFrame
df_features = client.query(sql).to_dataframe()

print(f"2. Saving features to: {features_table_id}...")

# Upload the engineered features to a permanent BigQuery table
pandas_gbq.to_gbq(
    dataframe=df_features,
    destination_table=features_table_id,
    project_id=project_id,
    if_exists='replace'
)

print("   Success! Training data ready.")

クエリを理解する

  1. ST_DWITHIN: この地理空間関数は、各サイトの場所の周囲に 500 メートルのバッファを作成し、その半径内にあるすべての Places Insights ポイントを特定します。
  2. COUNTIF: この関数は、各サイトの特定の場所タイプ(「ジム」、「学校」など)の密度を計算します。これらのカウントは、ML モデルの入力特徴(X)になります。
  3. pandas_gbq.to_gbq: この関数は、クエリ結果を新しいテーブル(site_features)に保持します。この永続テーブルは、BigQuery ML モデルのクリーンなトレーニング データセットとして機能します。

より高度な実際のアプリケーションでは、複数の距離(250 m、500 m、1 km など)で特徴を計算し、ratingprice_levelregular_opening_hours などの他の Places Insights 属性を検討してください。Places Insights の属性の完全なリストについては、サポートされている場所のタイプコアスキーマのリファレンスをご覧ください。

BigQuery ML を使用してモデルをトレーニングする

設計された特徴が site_features テーブルに保存されたので、線形回帰モデルをトレーニングできます。

このモデルは、各環境特徴(X)の最適な重み(β)を学習して、サイトのパフォーマンス(Y)を予測します。

イメージ

ロバスト スケーリングで外れ値を処理する

地理空間データには、標準の線形モデルを歪める可能性のある極端な外れ値が含まれていることがよくあります。たとえば、ロンドンのウエストエンドにあるサイトの半径 500 メートル以内には 200 軒のレストランがあるのに対し、郊外のサイトには 2 軒しかない場合があります。標準スケーリング(平均/標準偏差)を使用すると、外れ値(200)によって分布が歪み、モデルがその極端な値に適合することを優先するようになります。

この問題を解決するために、モデル定義内で Robust ScalingML.ROBUST_SCALER)を使用します。この手法では、中央値と四分位範囲(IQR)に基づいて特徴をスケーリングするため、モデルは外れ値に対して回復力があり、サイトの一般的な分布から学習できます。

モデルを作成する

BigQuery で次の SQL クエリを実行して、モデルを作成してトレーニングします。

TRANSFORM 句を使用して、すべての入力特徴量にロバスト スケーリングを適用します。また、optimize_strategy = 'NORMAL_EQUATION' は、一般的な店舗のポートフォリオなど、比較的小さなデータセットに対して最も効率的なトレーニング方法であるため、optimize_strategy = 'NORMAL_EQUATION' も設定します。最後に、パフォーマンスの高い外れ値(store_performance < 75)を除外して、モデルが一般的な成長パターンを予測することに集中できるようにします。

CREATE OR REPLACE MODEL `your_project.your_dataset.site_performance_model`
TRANSFORM(
  store_performance,
  -- Feature Engineering inside the model artifact
  -- These stats are calculated on the TRAINING split only
  ML.ROBUST_SCALER(gym_count) OVER() AS scaled_gym_count,
  ML.ROBUST_SCALER(restaurant_count) OVER() AS scaled_restaurant_count,
  ML.ROBUST_SCALER(school_count) OVER() AS scaled_school_count,
  ML.ROBUST_SCALER(transit_count) OVER() AS scaled_transit_count,
  ML.ROBUST_SCALER(clothing_store_count) OVER() AS scaled_clothing_store_count
)
OPTIONS(
    model_type = 'LINEAR_REG',
    input_label_cols = ['store_performance'],

    -- OPTIMIZATION PARAMETERS
    optimize_strategy = 'NORMAL_EQUATION', -- Exact mathematical solution (fast for small data)
    data_split_method = 'AUTO_SPLIT',      -- Automatically reserves ~20% for evaluation

    -- DIAGNOSTICS
    enable_global_explain = TRUE -- Essential to see feature importance
)
AS
SELECT
    gym_count,
    restaurant_count,
    school_count,
    transit_count,
    clothing_store_count,
    store_performance
FROM
    `your_project.your_dataset.site_features`
WHERE
    store_performance < 75;

モデルのパフォーマンスを評価する

サイトのパフォーマンスを左右する要因に関するモデルの分析情報を信頼するには、まずモデルの予測が正確であることを確認する必要があります。

トレーニング後、ML.EVALUATE 関数を使用して、トレーニング中に使用されなかったホールドアウト データセットに対してモデルの予測を評価します。

SELECT
  *
FROM
  ML.EVALUATE(MODEL `your_project.your_dataset.site_performance_model`);

R2 スコアr2_score)と平均絶対誤差mean_absolute_error)をチェックして、モデルを本番環境で使用できるかどうかを判断します。

  • R2 スコアは、パフォーマンスの分散のうち、外部の環境要因(近くの POI)によって実際に説明される割合を測定します。R2 スコアが 0.70 の場合、サイトの成功の 70% がローカル環境に関連していることを意味します。1.0 に近いほど、環境アメニティとサイトのパフォーマンスの相関関係が強くなります。
  • MAE は、ポイントの平均誤差を示します。たとえば、MAE が 1.5 の場合、モデルの予測は通常、実際のパフォーマンス スコアの +/- 1.5 ポイントの範囲内になります。

スコアが低い場合のトラブルシューティング

R2 スコアが低い場合は、次の改善策を検討してください。

  • 機能タイプを拡張する: クエリにさまざまな場所のタイプtourist_attractionsubway_station など)を追加します。
  • 商圏半径を調整する: ST_DWITHIN の距離を変更します。半径 500 メートルは、コーヒー ショップには広すぎるかもしれませんが、家具店には狭すぎる可能性があります。
  • データサイズを増やす: 統計的に有意なパターンを見つけるのに十分な店舗の場所でトレーニングしていることを確認します。

H3 空間インデックスを使用して都市をスコアリングする

H3 空間インデックスを使用して、ロンドンの都市を六角形のセル(解像度 8、約 0.7 km²)の均一なグリッドに分割します。これらのセルに Places Insights データを集約することで、トレーニング済みのモデルをすべての地域に適用し、上位のパフォーマンスを誇るサイトの環境プロファイルに一致する可能性の高いエリアを特定できます。

見込み顧客発掘クエリを実行する

このグリッドを生成するために、Places Insights データセットで提供される PLACES_COUNT_PER_H3 関数を使用します(詳しくは、Places Count 関数を使用して Places Insights をクエリするをご覧ください)。この関数は、1 回のオペレーションで H3 グリッド セルの POI 数を計算します。

次の SQL クエリを実行して、3 つのステップを 1 回の実行で実行します。

  1. H3 のインデックス登録とカウント: JSON 構成オブジェクトを使用して PLACES_COUNT_PER_H3 を呼び出し、ロンドンの中心部から半径 25 km 以内のすべての営業中の場所を検索します。このクエリは、アメニティ タイプ(ジム、学校など)ごとに個別に実行し、UNION ALL を使用して結合します。
  2. ピボット(特徴量エンジニアリング): ML モデルは個別の特徴列(gym_countrestaurant_count など)を想定しているため、セルをグループ化し、条件付き集計 (SUM(IF(...))) を使用して、データを正しいスキーマにピボットします。
  3. 予測: ピボットされたグリッド特徴を ML.PREDICT 関数に直接渡して、近隣地域ごとにパフォーマンス スコアを生成します。
WITH combined_counts AS (
    -- Gyms
    SELECT h3_cell_index, geography, count, 'gym' AS type
    FROM `places_insights___gb.PLACES_COUNT_PER_H3`(
        JSON_OBJECT(
            'geography', ST_BUFFER(ST_GEOGPOINT(-0.1278, 51.5074), 25000), -- 25km radius around London
            'h3_resolution', 8,
            'business_status', ['OPERATIONAL'],
            'types', ['gym']
        )
    )
    UNION ALL
    -- Restaurants
    SELECT h3_cell_index, geography, count, 'restaurant' AS type
    FROM `places_insights___gb.PLACES_COUNT_PER_H3`(
        JSON_OBJECT(
            'geography', ST_BUFFER(ST_GEOGPOINT(-0.1278, 51.5074), 25000),
            'h3_resolution', 8,
            'business_status', ['OPERATIONAL'],
            'types', ['restaurant']
        )
    )
    UNION ALL
    -- Schools
    SELECT h3_cell_index, geography, count, 'school' AS type
    FROM `places_insights___gb.PLACES_COUNT_PER_H3`(
        JSON_OBJECT(
            'geography', ST_BUFFER(ST_GEOGPOINT(-0.1278, 51.5074), 25000),
            'h3_resolution', 8,
            'business_status', ['OPERATIONAL'],
            'types', ['school']
        )
    )
    UNION ALL
    -- Transit Stations
    SELECT h3_cell_index, geography, count, 'transit_station' AS type
    FROM `places_insights___gb.PLACES_COUNT_PER_H3`(
        JSON_OBJECT(
            'geography', ST_BUFFER(ST_GEOGPOINT(-0.1278, 51.5074), 25000),
            'h3_resolution', 8,
            'business_status', ['OPERATIONAL'],
            'types', ['transit_station']
        )
    )
    UNION ALL
    -- Clothing Stores
    SELECT h3_cell_index, geography, count, 'clothing_store' AS type
    FROM `places_insights___gb.PLACES_COUNT_PER_H3`(
        JSON_OBJECT(
            'geography', ST_BUFFER(ST_GEOGPOINT(-0.1278, 51.5074), 25000),
            'h3_resolution', 8,
            'business_status', ['OPERATIONAL'],
            'types', ['clothing_store']
        )
    )
),
aggregated_features AS (
    -- Pivot the stacked rows back into standard feature columns for the ML Model
    SELECT
        h3_cell_index AS h3_index,
        ANY_VALUE(geography) AS h3_geography,
        SUM(IF(type = 'gym', count, 0)) AS gym_count,
        SUM(IF(type = 'restaurant', count, 0)) AS restaurant_count,
        SUM(IF(type = 'school', count, 0)) AS school_count,
        SUM(IF(type = 'transit_station', count, 0)) AS transit_count,
        SUM(IF(type = 'clothing_store', count, 0)) AS clothing_store_count
    FROM
        combined_counts
    GROUP BY
        h3_cell_index
)

-- Feed the pivoted features into the model
SELECT
    h3_index,
    predicted_store_performance,
    h3_geography,
    gym_count,
    restaurant_count
FROM
    ML.PREDICT(MODEL `your_project.your_dataset.site_performance_model`,
      (SELECT * FROM aggregated_features)
    )
ORDER BY
    predicted_store_performance DESC;

結果を解釈する

このクエリは、各行がロンドンの六角形のエリアを表すテーブルを返します。

  • h3_index: 六角形のセルの固有識別子。
  • predicted_store_performance: 周囲の環境のみに基づいて、このセルにあるサイトのモデルの推定スコア。
  • h3_geography: セルのポリゴン ジオメトリ。次のステップで可視化に使用します。

値が高いほど、学校、ジム、交通機関の密度が、最も成功している既存のサイト周辺で見つかったパターンと一致していることを示します。

見込み顧客マップを可視化する

データを実用的なものにするには、結果を地図上に可視化します。表形式の出力では未加工のスコアが提供されますが、マップでは、リストでは明らかでない、潜在力の高い空間クラスタと回廊が明らかになります。

付属のノートブックでは、geopandas ライブラリを使用して H3 ポリゴン ジオメトリを解析し、folium を使用してインタラクティブな地図をレンダリングします。

結果は、各六角形セルが予測スコアに応じて色分けされたコロプレスマップになります。

イメージ

地図を解釈する:

  • ホットスポット(黄色/緑色): 予測パフォーマンス スコアが高いエリアです。成功したサイトと相関関係のある学校、ジム、交通機関の最適な密度を備えています。これらは、新しいサイトの選定に最適な候補です。
  • コールドスポット(紫): これらのエリアには、上位のパフォーマンスを発揮しているエリアの近くにあるような環境機能がありません。
  • インタラクティブな検査: ノートブック環境で、任意のセルにカーソルを合わせると、その特定のスコアに貢献したアメニティの具体的な数(「ジム: 12」など)が表示されます。

まとめ

内部の運用データとプレイス インサイトを組み合わせて、サイトのパフォーマンスを診断できました。モデルの重みを分析することで、既存の指標と相関関係のある特定の近隣地域の特性を特定しました。H3 空間インデックスを使用して、この分析を数百のサイトからロンドン全域の数千の潜在的な近隣地域に拡大しました。

次のアクション

  • 特徴エンジニアリングを拡張する: クエリにさらに具体的な場所のタイプを追加して、ニッチな来店促進要因を把握します。
  • 高度なモデルを探索する: 線形回帰は明確な説明可能性を提供しますが、BigQuery ML の BOOSTED_TREE_REGRESSOR と適切な交差検証戦略を組み合わせて、非線形関係を捉えることを試してください。
  • 地図を運用する: Maps JavaScript API を使用して H3 グリッドの結果をカスタム ダッシュボードにエクスポートし、これらの分析情報をチームと共有します。

寄稿者