Google アナリティクスの UI と BigQuery エクスポートのギャップを埋める

Minhaz Kazi(Google アナリティクス デベロッパー アドボケイト) - 2023 年 4 月


「でも、どうして数字が UI と合わないんだろう?」

BigQuery で GA4 プロパティのイベント エクスポート データを扱ったことがあれば、きっと一度は疑問に思ったことがあるはずです。もっと困るのは、他の人から同じ質問をされた場合です。そして、なんとか回答しようとしているときに追い打ちをかけてくるのがこの質問です。

「で、どこにそう書いてあるの?」

この記事では、両方の問題に光を当てていきたいと思います。

数値の差異について詳しく見ていく前に、BigQuery イベント エクスポート データの本来の用途を理解しておくことが重要です。Google アナリティクスのユーザーは、いずれかの収集方法(Google タグGoogle タグ マネージャーMeasurement ProtocolSDK、またはデータ インポート)を通して、Google アナリティクスに収集データを送信します。Google アナリティクスは各 GA プロパティの設定に応じて、収集したデータにさまざまな価値付加を行ったうえで、標準レポート サーフェス(通常のレポートデータ探索ツールData API)に出力します。価値付加とはたとえば、Google シグナルの組み込み、モデリング、トラフィック アトリビューション、予測などを指します。

Google アナリティクスの標準のレポート画面は、最大限の価値を可能な限りスムーズに提供することを目指した設計となっています。しかしながらユーザーのニーズはさまざまで、Google アナリティクスによる価値付加をさらに拡充したいケースや、出力を抜本的にカスタマイズしたいケースもあるはずです。こうした運用の起点としてご用意しているのが、BigQuery イベント エクスポートです。BigQuery イベント エクスポートに含まれるのは、クライアントやアプリから Google アナリティクスに送信される、収集したままのデータです。前述の付加価値要素の多くについては、BigQuery イベント エクスポートには詳細なデータは含まれません。

このため、多くのユースケースにおいては、前述の付加価値要素に関する部分で、標準レポート サーフェスと BigQuery エクスポート データの間に完全な対応関係を求めることは想定されていません。それぞれのデータの中で整合性が保たれており、収集した情報とも合致していれば、問題ないと考えていいでしょう。

それでは、データに差異が生じる具体的な原因と、(可能な場合は)影響を緩和する方法を確認していきましょう。なお、この記事では BigQuery の日次イベント エクスポートに絞って説明し、ストリーミング エクスポートは扱いません。

サンプリング

BigQuery Export のデータと、標準レポート、Data API レポート、データ探索ツールレポートを正確に比較するには、それらがサンプリング データに基づいたものではないことを確認します。詳細とサンプリングへの対処方法は、GA4 のデータ サンプリングに関する記事でご確認いただけます。

アクティブ ユーザー

GA4 プロパティでイベントを 1 件でも発生させたユーザーの数をカウントした場合、得られるのは「合計ユーザー数」指標の値です。「合計ユーザー数」指標は、GA4 の UI 内でもデータ探索ツールを通して利用できますが、GA4 で主に使用されるユーザー数の指標は「アクティブ ユーザー数」であることに注意が必要です。GA4 の UI やレポート類で単に「ユーザー数」とあれば、それは通常「アクティブ ユーザー数」を指しています。したがって、BigQuery のデータをもとにユーザー数を算出する場合、Google アナリティクスの UI と比較可能な値を得るには、アクティブ ユーザーだけを抽出してカウントする必要があります。適切な計算方法は、使用しているレポート用識別子によっても異なります。

技術的な実装

BigQuery イベント エクスポート データで、互いに異なるユーザー ID の数をカウントした場合、得られるのは「合計ユーザー数」です。次のサンプルクエリでは、user_pseudo_id をもとに、合計ユーザー数と新規ユーザー数の両方を求めています。

-- Example: Get 'Total User' count and 'New User' count.

WITH
  UserInfo AS (
    SELECT
      user_pseudo_id,
      MAX(IF(event_name IN ('first_visit', 'first_open'), 1, 0)) AS is_new_user
    -- Replace table name.
    FROM `bigquery-public-data.ga4_obfuscated_sample_ecommerce.events_*`
    -- Replace date range.
    WHERE _TABLE_SUFFIX BETWEEN '20201101' AND '20201130'
    GROUP BY 1
  )
SELECT
  COUNT(*) AS user_count,
  SUM(is_new_user) AS new_user_count
FROM UserInfo;

アクティブなユーザーのみ選択するには、クエリの対象を、is_active_usertrue であるイベントに限定します。

-- Example: Get exact and approximate Active User count.

WITH
  ActiveUsers AS (
    SELECT
      user_pseudo_id
    -- Replace table name.
    FROM `bigquery-public-data.ga4_obfuscated_sample_ecommerce.events_*`
    -- Replace date range.
    WHERE _TABLE_SUFFIX BETWEEN '20201101' AND '20201130'
      AND is_active_user
    GROUP BY 1
  )
SELECT
  COUNT(DISTINCT user_pseudo_id) AS exact_active_user_count,
  APPROX_COUNT_DISTINCT(user_pseudo_id) AS approx_active_user_count
FROM ActiveUsers;

HyperLogLog++

Google アナリティクスは、一般的な指標(アクティブ ユーザー数、セッション数など)の基数を、HyperLogLog++(HLL++)アルゴリズムによって推定しています。よって、これらの指標のユニーク カウントを UI 内または API 経由で参照した場合、得られるのは一定の精度を持つ近似値です。これに対して BigQuery では詳細なデータを参照できるため、各指標の厳密な基数を計算することが可能です。そのため、両者の指標の値にはわずかな割合で差異が生じることがあります。たとえばセッション数の精度は、95% 信頼区間で ±1.63% などになります。精度は指標ごとに異なり、信頼区間によっても変化します。HLL++ の精度(適合率)パラメータに応じた、各信頼区間における精度は、HLL++ スケッチでご確認いただけます。

技術的な実装

Google アナリティクスにおける HLL++ の実装と、同じ機能を BigQuery のクエリで再現する方法については、Google アナリティクスにおけるユニーク カウントの近似値をご覧ください。

データ収集の遅延

日次エクスポート テーブルは、Google アナリティクスがその日のイベントの収集を終えてから作成されます。該当日のタイムスタンプを持つイベントが後追いで追加されることもあるため、日次テーブルの更新は、その日が終わってから最大で 72 時間後まで続きます(詳細と具体例をご覧ください)。このことは、使用している Firebase SDK または Measurement Protocol 実装からオフラインのイベントや遅延イベントが送られてくる場合に問題となります。前述の 72 時間の間に、標準レポート サーフェスと BigQuery のデータ更新がそれぞれどのタイミングで行われるかによって、両者のデータに差異が生じる可能性があるためです。このような実装において両者のデータを比較する場合は、72 時間以上前のデータを使用しましょう。

基数の大きいレポート

たとえば、通常のレポートまたは Data API を使用している場合に、レポートを通して参照するデータの規模が大きく、基数の大きいディメンションが含まれていたとしましょう。高基数ディメンションを含むレポートは、もとになっているテーブルの基数の上限を超えてしまう可能性があります。この場合、Google アナリティクスは頻度の低い値を「(other)」というラベルでグループ化します。

以下は単純化した小スケールの例ですが、もとになっているテーブルの基数の上限が 10 行であれば、このように処理されます。

「(other)」行を含む集計済みテーブルと元データの違いを示す、単純化された例

このように、イベントの総数は集計後のテーブルでもそのままですが、頻度の低い値がグループ化されており、テーブルを任意のディメンションによって集計し直すことはできなくなっています(集計済みのテーブルからは、たとえば特定の都市のイベント数を高い精度で割り出すことができません)。集計データをいずれかのディメンションでフィルタ処理すれば、影響はさらに大きくなります。

「(other)」行への集約が発生するのは、レポート モジュールと Data API で、レポートが基数の上限を超えた場合のみです。BigQuery から計算を行った場合は、常に元データ(最も詳細なデータ行)が返されます。「(other)」行の詳細と、発生を回避するためのベスト プラクティスも併せてご覧ください。

Google シグナル

Google アナリティクス 4 プロパティで Google シグナルを有効化すると、さまざまなメリットがあります。プラットフォームやデバイスをまたいだユーザー重複除去もそのひとつです。User-ID と Google シグナルを有効化していない場合、ある人が 3 種類のブラウザからウェブサイトを訪問すれば、Google アナリティクスはそれを 3 人の異なるユーザーと認識し、BigQuery エクスポート データには 3 つの異なる user_pseudo_id が含まれることになります。これに対して、Google シグナルが有効化されており、ユーザーが 3 種類のブラウザで同じ Google アカウントにログインしていた場合は、Google アナリティクスはこれを 1 人のユーザーと認識し、標準レポート サーフェスでもそのように表示されます。ただし、BigQuery 側では 3 つの異なる user_pseudo_id が使用されたままになります。BigQuery エクスポート データでは、Google シグナルの情報を利用できないためです。したがって、Google シグナルのデータを使ったレポートでは、BigQuery エクスポート データよりもユーザー数が少なくなることが一般的です。

この差異を軽減したい場合は、GA4 プロパティで User-ID を実装し、Google シグナルも有効化するのがおすすめです。これにより、user_id に基づく重複除去が最初に行われます。ログイン中のユーザーについては、BigQuery が自動的に値を入力した user_id フィールドを計算に使用できます。ログインしていないユーザー(user_id を持たないセッション)については、重複除去の基準は Google シグナルのままです。

標準レポート サーフェスの一部のレポートはしきい値の適用を受けるため、一部のデータが返されない点にも注意しましょう。しきい値の適用対象となり得る情報の多くは、BigQuery エクスポート データでは利用できないことが一般的です。

ウェブサイトやモバイルアプリの「同意モード」とは、Cookie やアプリ識別子についてのユーザーの同意ステータスを Google に伝達できる仕組みです。ユーザーが同意を拒否した場合、GA4 はコンバージョン モデリング行動モデリングによって、データ収集のギャップを補完します。このようなモデル推計によるデータは、BigQuery イベント エクスポートでは利用できません。同意モードが実装されている場合、BigQuery のデータセットには、Google アナリティクスが収集した Cookie 不使用の ping が含まれており、各セッションはそれぞれ異なる user_pseudo_id を持ちます。モデリングによる補完が行われているため、標準レポート サーフェスと BigQuery の詳細データの間には差異が生じます。たとえば、行動モデリングによって、非同意ユーザーが複数のセッションを発生させたケースが想定されるため、アクティブ ユーザー数が BigQuery エクスポート データよりも少なく表示される可能性があります。

ここでも、影響を軽減するには GA4 プロパティに User-ID を実装するのがおすすめです。user_id とカスタム ディメンションは、ユーザーの同意ステータスを問わず、BigQuery にエクスポートされます。

トラフィック アトリビューション データ

BigQuery で利用できるのは、ユーザー(初回訪問)レベルおよびイベントレベルのトラフィック アトリビューション データです。これらは、収集データです。これに対して Google アナリティクスは、セッション レベルで独自のアトリビューション モデルを実装していますが、その情報は BigQuery のエクスポート データからは直接利用できず、利用可能なデータから正確に算出することもできません。ユースケースによっては、たとえば BigQuery データセットを任意の関連自社データと結合して、独自のアトリビューション モデルを構築するのも一案です。将来的には、トラフィック アトリビューション関連の収集データが追加され、BigQuery イベント エクスポートを通して利用できるようになる可能性もあります。

一般的な計算ミス

  • 計算方法: BigQuery でさまざまな指標を計算する際は、正しい計算方法を選ぶ必要があります。たとえば以下の点に注意しましょう。
    • セッション数をカウントする際、Google アナリティクス 4 プロパティでは、user_pseudo_id / user_idga_session_id の組み合わせによってセッションが識別されるため、時間帯は影響しません。一方、ユニバーサル アナリティクスでは、午前 0 時にセッションがリセットされていました。ユニバーサル アナリティクスの方式で計算した 1 日ごとのセッション数をそのまま合計してしまうと、日をまたいだセッションは重複してカウントされるため、合計セッション数が過大になります。
    • 使用しているレポート用識別子によっては、ユーザー数の計算方式をアップデートする必要があります。
  • ディメンションと指標のスコープ: 計算で使用するスコープ(ユーザー、セッション、アイテム、またはイベント)は正しく選びましょう。
  • タイムゾーン: BigQuery エクスポート データにおいて、event_date はレポートのタイムゾーンに対応しますが、event_timestamp は UTC のタイムスタンプ(マイクロ秒単位)です。このため、UI との比較に適した数値を得るには、クエリ内で event_timestamp を使用する場合は、レポートのタイムゾーンに合わせて調整する必要があります。
  • データのフィルタリングとエクスポートの上限: BigQuery イベント エクスポートにデータのフィルタリングを適用している場合や、日次イベント エクスポートの量が上限を超えた場合は、BigQuery イベント エクスポートのデータは、標準レポート サーフェスと一致しません。

今回の投稿は以上です。ご自身のプロジェクトに合ったソリューションを見つけて、ご活用いただければ幸いです。ご質問があれば Google アナリティクスの Discord サーバーで受け付けていますので、ぜひご活用ください。