青の統計学-DS Playground-

利用深度 mart:スコア・tier・分布の設計

Stage 4 — 第2章 | dbt入門カリキュラム 推定学習時間:45〜55分 | 難易度:★★★★☆


この章で学ぶこと

前章 では、課金状態を intermediate に固定しました。 Activity mart が DAU など 「来たかどうか」 を数えるのに対し、Engagement mart は 「どれだけ・どれだけ広く・どれだけ深く使っているか」 を会員単位で表します。

エンゲージメント分析は、Recency(最終利用)、Consistency(継続頻度)、Breadth(機能の広さ)、Depth(完了量)など複数の概念を組み合わせます。 これらを mart ごとに別定義すると、power user の閾値や dormant の日数が表ごとにずれます。

dbt では 行レベル mart(1 会員 1 行)と 分布 mart(セグメント別の構成比)を分け、後者をダッシュボードの SSOT にするパターンが一般的です。 行レベルには疑似匿名キーを使い、公開用途には集計済み分布を優先します。

まず dbt の作法を整理し、続けて DS Playground の fct_user_engagement_currentfct_user_engagement_distribution_current を読み解きます。

この章を終えると、こんなことができるようになります:

  • Recency / Consistency / Breadth / Depth / Intensity の 5 概念を列名と対応づけられる
  • engagement_tier の 5 段階定義を説明できる
  • anon_user_key疑似匿名 であり公開安全ではない理由を説明できる
  • 行レベル mart と分布 mart の使い分けを説明できる

Engagement 分析

DAU / WAU / MAU は アクティブの有無 を期間単位で数えます。 Engagement はその延長線上にあり、残っているか・深いか・広いか を会員単位で測ります。

概念 典型列 意味
Recency days_since_last_activity 最後に利用したのはいつか
Consistency active_days_30d, active_weeks_12w 戻ってくる頻度
Breadth activity_types_used, categories_touched 触れた機能・カテゴリの広さ
Depth items_completed, problems_attempted 完了・保存の量
Intensity usage_intensity_score 上記を組み合わせた ヒューリスティック
Tier engagement_tier 人が読めるラベル

Intensity スコアや tier は プロダクト利用強度 の内部モニタリング指標です。 学力・合格力・購買意欲そのものを表すスコアではありません。YAML の caveats にもその旨を書きます。

flowchart TB ACT["activity / 行動イベント集計"] MEM["会員状態・属性"] ROW["行レベル engagement mart
1 会員 1 行"] DIST["分布 mart
status × goal × tier"] ACT --> ROW MEM --> ROW ROW --> DIST

行レベル mart の grain は 1 行 = 1 会員 です。 分布 mart は行レベルを GROUP BY し、構成比(share) を出します。 grain と business question が異なるため、1 表に混ぜません(Mart 設計)。


tier と intensity の設計

engagement_tier は、閾値ベースの 5 段階ラベル です。 registered_only(行動ゼロ)、activated(1 回以上)、engaged(一定頻度)、power_user(高頻度 + 深度)、dormant(長期非活性)——このような段階分けは SaaS でよく見られます。

-- tier 判定(概念)
          case
            when active_days_lifetime = 0 then 'registered_only'
            when days_since_last_activity > 90 then 'dormant'
            when active_days_30d >= 8
              and (problems_attempted >= 30
                or curriculum_pages_completed >= 5
                or mock_exams_saved >= 2)
              then 'power_user'
            when active_days_30d >= 3 or active_weeks_12w >= 3 then 'engaged'
            else 'activated'
          end as engagement_tier
          

閾値は 設定可能なヒューリスティック です。変更時は YAML・singular test・ダッシュボードを同時更新します。

usage_intensity_score は 0〜100 に clamp した加重式(例: active_days_30d * 4 + mock_exams_saved * 5 + ...)です。 singular test で範囲(0〜100)を守り、スコア列の契約を CI で固定します。


疑似匿名キーとガバナンス

行レベル mart では、raw user_id の代わりに ハッシュ化キー(例: md5(user_id::text))を露出することがあります。 これは 疑似匿名(pseudonymous) であり、完全匿名化ではありません。

内部キーとの対応表があれば再識別可能です。 Engagement mart の行レベル出力を外部公開せず、集計分布 mart をダッシュボード SSOT にする——この使い分けがガバナンスの要です。

ガバナンス実践 の「利用目的に応じた最小露出」と一致します。

誤解 事実
md5 だから公開 OK 内部キーとの対応表があれば再識別可能
engagement mart は外部共有可能 集計分布 mart を優先
カリキュラムに実キーを載せてよい 載せない

Engagement mart ファミリー

DS Playground では Engagement ファミリーに 2 モデルがあります。

  • fct_user_engagement_current — 1 会員 1 行(anon_user_key
  • fct_user_engagement_distribution_current — status × goal × tier の分布

入力の組み立て

business question: 「各会員は今どの程度プロダクトを使っているか」

flowchart TB M["int_member_status_current"] --> C["combined CTE"] A["int_user_activity_events 集計"] --> C P["stg_supabase__problem_attempts 集計"] --> C CU["user_curriculum_page_progress 集計"] --> C EX["exam_attempt_events 集計"] --> C SV["member_survey_responses 集計"] --> C SK["skill_check_results"] --> C C --> OUT["fct_user_engagement_current"]

user_id は内部 JOIN に使い、最終 SELECT では anon_user_key = md5(user_id::text) を主キー相当として露出します。

engagement_tier 語彙

Tier 定義 プロダクト上の読み
registered_only Learning Action ゼロ 登録したが未体験
activated 1 回以上は使ったが engaged 閾値未満 初期活性
engaged 30 日で 3 日以上 or 12 週で 3 週以上 習慣化途中
power_user 高頻度 + 深度(演習/カリキュラム/模試) コアユーザー
dormant 90 日超非活性 復帰候補

fct_user_engagement_distribution_current

business question: 「会員全体の engagement 構成はどうなっているか」

grain: 1 行 = member_status × primary_goal × engagement_tier

select
            member_status,
            coalesce(primary_goal, 'unset') as primary_goal,
            engagement_tier,
            count(*) as members,
            safe_ratio(members, total_members) as member_share,
            avg(usage_intensity_score) as avg_usage_intensity_score
          from fct_user_engagement_current
          group by 1, 2, 3;
          
mart 行レベル ダッシュボード向き
fct_user_engagement_current あり(anon) 内部調査・サンプル確認
fct_user_engagement_distribution_current なし Metabase 主役(PII リスク低)

exposure metabase_product_health_dashboard分布 mart を depends_on に含みます。

free / premium 比較の読み方

分布 mart で member_status を軸に power_user share を比較する例:

select
            member_status,
            engagement_tier,
            member_share
          from fct_user_engagement_distribution_current
          where primary_goal = 'unset'  -- 例: 全体
          order by 1, 2;
          

前章 で学んだ current-state の member_status であること(過去 as-of 不可)を必ず併記してください。


体系コラム:カリキュラム上の位置づけ

項目 内容
Stage / 章 Stage 4 — 第2章
今回の論点 5 概念、tier、intensity、anon キー、分布 mart
前章との接続 Monetization status
次章への伏線 Survey mart

まとめ

Engagement は DAU の延長線上にあり、「残っているか・深いか」 を測ります。 DS Playground では activity・practice・curriculum・exam・survey・skill check を組み合わせた行レベル mart と、その分布 mart を分け、会議では後者を SSOT にしています。

行レベルは内部、分布はダッシュボード——この使い分けがガバナンスの要です。


関連教材


確認問題

問題 1

エンゲージメント tier で「行動 1 件もない登録ユーザー」を分ける 主な理由 はどれですか。

A. SQL が短いから
B. 登録のみと、実際に行動したユーザーを区別するため
C. incremental だから
D. seed が必須だから

正解: B


問題 2

分布(distribution)mart を raw 行 mart とは 別モデル にする主な理由はどれですか。

A. PII を削除するため
B. grain と business question が異なるため(集計済み vs 1 行 1 ユーザー)
C. source() が使えないため
D. YAML が書けないため

正解: B


問題 3

疑似匿名キー(hashed user key)について 正しい 説明はどれですか。

A. 公開 Web にそのまま載せてよい完全匿名 ID
B. 内部向けの識別子であり、行レベル出力の公開には別途ガバナンスが必要
C. OLTP の主キーそのもの
D. BI ツールのユーザー ID

正解: B


用語メモ(この章)

用語 意味(この章での使い方)
Engagement 利用の深さ・広さ・継続性
engagement_tier 閾値ベースの 5 段階ラベル
usage_intensity_score 0〜100 の内部ヒューリスティック
分布 mart セグメント別構成比の集計表
疑似匿名 ハッシュ化キー。完全匿名ではない