一个平均 Firebase 活跃用户指标(DAU、WAU、MAU)应该是多少?
Should one average Firebase Active User Metrics (DAU, WAU, MAU)?
我正在尝试了解在当前 Firebase "Active" 用户指标报告(查看下图)中按月报告是否更好,或者自行计算并报告 在特定时期内每个指标的平均值。
乍一看,仪表板显示了 2018 年 12 月的 1 天、7 天和 28 天活跃用户,但实际上它只是所选日期范围值的最后一天显示(在右侧)。很高兴知道这一点,但在我的逐月分析中仅比较最后日期的值有点误导。另一种方法是自行计算选定时间段内的平均值:
应用于Firebase Demo数据集,得到如下数字:
Firebase 仪表板:
- 28 天活跃用户:8661
- 7 天活跃用户:3874
- 1 天活跃用户:1111
我计算的平均值:
- 28 天活跃用户:8762
- 7 天活跃用户:3663
- 1 天活跃用户:1112
此处的增量差异很小,但我发现我们的应用程序存在一些显着差异,该应用程序每月有数百万活跃用户。
问题:
- 如果您目前正在使用 Firebase,您如何报告它?
- 您是复制并粘贴所选时间段的最后一天并报告一个月,还是对每个 1/7/28 天指标进行平均以更好地表示该月?
- 如果你对你的指标进行平均,你能解释一下原因吗?
为了回答这个问题,我想先回顾一下 Google 的适用定义,然后 运行 进行计算(最后一次回顾:2021 年 7 月)。
Google 给出了以下定义:
GA4 - Automatically collected events
session_start
(应用程序、网络)- 当用户使用应用程序或网站时
user_engagement
(app, web) - 定期,当应用程序在前台或网页处于焦点时
带参数:engagement_time_msec
GA4 - How the number of sessions is calculated
Sessions
:在您的网站或应用程序上开始的会话数(触发了 session_start 事件)。
App session timeout duration
:当应用程序移至后台时,应用程序会话开始超时,但您可以选择通过包含 extend_session 参数(值为1) 应用程序在后台时发送的事件。如果您的应用经常在后台使用(例如导航和音乐应用),这将非常有用。通过 setSessionTimeoutDuration
方法更改应用会话的默认超时 30 分钟。
Engaged sessions
:持续 10 秒或更长时间,或具有 1 次或更多转化事件或 2 次或更多页面浏览的会话数。
Monthly (28-day), Weekly (7-day), and Daily (1-day) Active Users
日期范围,包括相对于上一个日期范围的百分比波动。一位活跃用户在设备前台使用了一个应用程序,并记录了一个 user_engagement 事件。
Daily user engagement
- 日期范围内每位用户的平均每日参与度,包括与上一个日期范围相比的百分比波动。
我对定义的看法:
根据支持性 GA4/Firebase 文档,我(重新)总结了以下每个指标的定义。非常重要的一点是,只有 唯一身份用户 才应计入每个指标(给定选定的日期范围)。不需要 UNNEST
因为我们已经在 event_name
级别查询,而不是 event_parameter
级别。
- 1 天活跃用户: 1 天 唯一 活跃用户参与在设备前台有一个应用 AND 在过去 1 天内(给定选定的日期范围)记录了一个
user_engagement
事件。
- 7 天活跃用户: 7 天 唯一 活跃用户参与在设备前台有一个应用 AND 在过去 7 天内(给定选定的日期范围)记录了一个
user_engagement
事件。
- 28 天活跃用户: 28 天 唯一 活跃用户参与在设备前台有一个应用 AND 在过去 28 天内(给定选定的日期范围)记录了一个
user_engagement
事件。
在下面的单元格中,您可以看到 12 月指标的计算方式:
计算每个指标/受众的方法:
- 使用以下公式计算特定月份的 DAU:
Average 1-day active user metric
。
- 使用以下公式计算特定月份的 WAU:
Average 7-day active user metric
。我通过对 12 月 7 日、14 日、21 日和 28 日的快照求平均值来计算的。
- 使用以下公式计算特定月份的 MAU:
Non-averaged 28-day active user metric
。不对这个指标的值进行平均的主要原因是,因为我只想获得整个月的一个快照。如果我在这里使用平均值,我也会考虑上个月的活跃用户。
1.a) 平均 1 天唯一活跃用户指标
# StandardSQL
SELECT
ROUND(AVG(users),0) AS users
FROM
(
SELECT
event_date,
COUNT(DISTINCT user_pseudo_id) AS users
FROM `<id>.events_*`
WHERE
event_name = 'user_engagement'
AND _TABLE_SUFFIX BETWEEN '20181201' AND '20181231'
AND platform = "ANDROID"
GROUP BY 1
) table
# or you could also use code below, but you will have to add in the remaining days' code to query against the entire month.
-- Set your variables here
WITH timeframe AS (SELECT DATE("2018-12-01") AS start_date, DATE("2018-12-31") AS end_date)
-- Query your variables here
SELECT ROUND(AVG(users),0) AS users
FROM
(
SELECT event_date, COUNT(DISTINCT user_pseudo_id) AS users
FROM `<id>.events_*`AS z, timeframe AS t
WHERE
event_name = 'user_engagement'
AND _TABLE_SUFFIX > FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 1 DAY))
AND _TABLE_SUFFIX <= FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL 0 DAY))
AND platform = "ANDROID"
GROUP BY 1
UNION ALL
SELECT event_date, COUNT(DISTINCT user_pseudo_id) AS users
FROM `<id>.events_*`AS z, timeframe AS t
WHERE
event_name = 'user_engagement'
AND _TABLE_SUFFIX > FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 2 DAY))
AND _TABLE_SUFFIX <= FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 1 DAY))
AND platform = "ANDROID"
GROUP BY 1
...
...
...
...
) avg_1_day_active_users
1.b) 平均 1 天唯一活跃用户指标
更新的版本计划 daily
到 BQ 目标 table daus_android_{run_time|"%Y%m%d"}
并具有写入首选项 WRITE_APPEND
,如下所示。我之前进行了深入研究,确定日内 -table 事件最多可能需要 48 小时才能传播到永久 BQ tables(因此查询中有 - 3 天)。
with base AS (
SELECT *
FROM `<id>.analytics_<number>.events_*`
WHERE (_TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 3 DAY)) AND _TABLE_SUFFIX < FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)))
AND platform = "ANDROID"
AND event_name = 'user_engagement'
), app AS (
SELECT
FORMAT_DATE('%Y%m%d', @run_date) AS _currentdate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 3 DAY)) AS _begindate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)) AS _enddate,
TIMESTAMP_DIFF(TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 2 DAY)), TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 3 DAY)), HOUR) AS _hoursdiff,
COUNT(DISTINCT user_pseudo_id) AS _uniqusers
FROM base
)
SELECT
app._currentdate,
app._begindate,
app._enddate,
app._hoursdiff,
app._uniqusers
FROM app;
1.c) 平均 1 天唯一活跃用户指标
WITH app as (
SELECT
FORMAT_DATE('%Y%m%d', @run_date) AS _currentdate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 3 DAY)) AS _begindate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)) AS _enddate,
TIMESTAMP_DIFF(TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 2 DAY)), TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 3 DAY)), HOUR) AS _hoursdiff,
COUNT(DISTINCT user_pseudo_id) AS _uniqusers
FROM `<gcp-project>.analytics_<id>.events_*`
WHERE
platform = "ANDROID"
AND event_name = 'user_engagement'
AND _TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 3 DAY))
AND _TABLE_SUFFIX < FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY))
)
SELECT
app._currentdate,
app._begindate,
app._enddate,
app._hoursdiff,
app._uniqusers
FROM app
2.a) 平均 7 天唯一活跃用户指标
-- Set your variables here
WITH timeframe AS (SELECT DATE("2018-12-01") AS start_date, DATE("2018-12-31") AS end_date)
-- Query your variables here
SELECT ROUND(AVG(users),0) AS users
FROM
(
SELECT COUNT(DISTINCT user_pseudo_id) AS users
FROM `<id>.events_*`AS z, timeframe AS t
WHERE
event_name = 'user_engagement'
AND _TABLE_SUFFIX > FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 7 DAY))
AND _TABLE_SUFFIX <= FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL 0 DAY))
AND platform = "ANDROID"
UNION ALL
SELECT COUNT(DISTINCT user_pseudo_id) AS users
FROM `<id>.events_*`AS z, timeframe AS t
WHERE
event_name = 'user_engagement'
AND _TABLE_SUFFIX > FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 14 DAY))
AND _TABLE_SUFFIX <= FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 7 DAY))
AND platform = "ANDROID"
UNION ALL
SELECT COUNT(DISTINCT user_pseudo_id) AS users
FROM `<id>.events_*`AS z, timeframe AS t
WHERE
event_name = 'user_engagement'
AND _TABLE_SUFFIX > FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 21 DAY))
AND _TABLE_SUFFIX <= FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 14 DAY))
AND platform = "ANDROID"
UNION ALL
SELECT COUNT(DISTINCT user_pseudo_id) AS users
FROM `<id>.events_*`AS z, timeframe AS t
WHERE
event_name = 'user_engagement'
AND _TABLE_SUFFIX > FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 28 DAY))
AND _TABLE_SUFFIX <= FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 21 DAY))
AND platform = "ANDROID"
) avg_7_day_active_users
2.b) 平均 7 天唯一活跃用户指标
更新的版本计划 daily
到 BQ 目标 table waus_android_{run_time|"%Y%m%d"}
,写入首选项 WRITE_APPEND
,可能看起来像:
with base AS (
SELECT *
FROM `<id>.analytics_<number>.events_*`
WHERE (_TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 9 DAY)) AND _TABLE_SUFFIX < FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)))
AND platform = "ANDROID"
AND event_name = 'user_engagement'
), app AS (
SELECT
FORMAT_DATE('%Y%m%d', @run_date) AS _currentdate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 9 DAY)) AS _begindate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)) AS _enddate,
TIMESTAMP_DIFF(TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 2 DAY)), TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 9 DAY)), HOUR) AS _hoursdiff,
COUNT(DISTINCT user_pseudo_id) AS _uniqusers
FROM base
)
SELECT
app._currentdate,
app._begindate,
app._enddate,
app._hoursdiff,
app._uniqusers
FROM app;
3.a) 非平均 28 天唯一活跃用户指标
# StandardSQL
-- Set your variables here
WITH timeframe AS (SELECT DATE("2018-12-01") AS start_date, DATE("2018-12-31") AS end_date)
-- Query your variables here
SELECT COUNT(DISTINCT user_pseudo_id) AS users
FROM `<id>.events_*`AS z, timeframe AS t
WHERE
event_name = 'user_engagement'
AND _TABLE_SUFFIX > FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 28 DAY))
AND _TABLE_SUFFIX <= FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL 0 DAY))
AND platform = "ANDROID"
3.b) 非平均 28 天唯一活跃用户指标
更新的版本计划 daily
到 BQ 目的地 table maus_android_{run_time|"%Y%m%d"}
,写入首选项 WRITE_APPEND
,可能看起来像:
with base AS (
SELECT *
FROM `<id>.analytics_<number>.events_*`
WHERE (_TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 30 DAY)) AND _TABLE_SUFFIX < FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)))
AND platform = "ANDROID"
AND event_name = 'user_engagement'
), app AS (
SELECT
FORMAT_DATE('%Y%m%d', @run_date) AS _currentdate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 30 DAY)) AS _begindate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)) AS _enddate,
TIMESTAMP_DIFF(TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 2 DAY)), TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 30 DAY)), HOUR) AS _hoursdiff,
COUNT(DISTINCT user_pseudo_id) AS _uniqusers
FROM base
)
SELECT
app._currentdate,
app._begindate,
app._enddate,
app._hoursdiff,
app._uniqusers
FROM app;
旁注:
- 我知道有些公司仍在计算他们 30 天的 MAU。因此,您必须进行测试,看看哪种方法最适合您的公司。
- 您可以根据上述示例计算自己的
DAU-to-MAU
比率或 WAU-to-MAU
比率,以确定您应用的 stickiness
- 我对 MAU 计算的唯一问题是它还没有考虑每个月的开始日期。也许可以取第 31 天 - 28 天、第 30 天 - 28 天、第 29 天 - 28 天、第 28 天 - 28 天的平均值 ...
- 我发现 Firebase 团队的示例 queries 也很有帮助,但他们的活跃指标仅涉及执行查询时的活跃用户数(查看下面的示例):
SELECT
COUNT(DISTINCT user_id)
FROM
/* PLEASE REPLACE WITH YOUR TABLE NAME */
`YOUR_TABLE.events_*`
WHERE
event_name = 'user_engagement'
/* Pick events in the last N = 20 days */
AND event_timestamp > UNIX_MICROS(TIMESTAMP_SUB(CURRENT_TIMESTAMP, INTERVAL 20 DAY))
/* PLEASE REPLACE WITH YOUR DESIRED DATE RANGE */
AND _TABLE_SUFFIX BETWEEN '20180521' AND '20240131';
忍者秘诀
要将您的团队“s/company”s/product 的关注点从 Vanity Metrics
转移到 Actionable Metrics
,请考虑将您的主要转化事件之一添加为上面的查询(例如 in_app_purchase
for e-commerce companies):
with base AS (
SELECT *
FROM `<id>.analytics_<number>.events_*`
WHERE (_TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 3 DAY)) AND _TABLE_SUFFIX < FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)))
AND platform = "ANDROID"
# AND event_name = 'user_engagement'
AND event_name = 'in_app_purchase'
), app AS (
SELECT
FORMAT_DATE('%Y%m%d', @run_date) AS _currentdate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 3 DAY)) AS _begindate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)) AS _enddate,
TIMESTAMP_DIFF(TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 2 DAY)), TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 3 DAY)), HOUR) AS _hoursdiff,
COUNT(DISTINCT user_pseudo_id) AS _uniqusers
FROM base
)
SELECT
app._currentdate,
app._begindate,
app._enddate,
app._hoursdiff,
app._uniqusers
FROM app;
我正在尝试了解在当前 Firebase "Active" 用户指标报告(查看下图)中按月报告是否更好,或者自行计算并报告 在特定时期内每个指标的平均值。
乍一看,仪表板显示了 2018 年 12 月的 1 天、7 天和 28 天活跃用户,但实际上它只是所选日期范围值的最后一天显示(在右侧)。很高兴知道这一点,但在我的逐月分析中仅比较最后日期的值有点误导。另一种方法是自行计算选定时间段内的平均值:
应用于Firebase Demo数据集,得到如下数字:
Firebase 仪表板:
- 28 天活跃用户:8661
- 7 天活跃用户:3874
- 1 天活跃用户:1111
我计算的平均值:
- 28 天活跃用户:8762
- 7 天活跃用户:3663
- 1 天活跃用户:1112
此处的增量差异很小,但我发现我们的应用程序存在一些显着差异,该应用程序每月有数百万活跃用户。
问题:
- 如果您目前正在使用 Firebase,您如何报告它?
- 您是复制并粘贴所选时间段的最后一天并报告一个月,还是对每个 1/7/28 天指标进行平均以更好地表示该月?
- 如果你对你的指标进行平均,你能解释一下原因吗?
为了回答这个问题,我想先回顾一下 Google 的适用定义,然后 运行 进行计算(最后一次回顾:2021 年 7 月)。
Google 给出了以下定义:
GA4 - Automatically collected events
session_start
(应用程序、网络)- 当用户使用应用程序或网站时user_engagement
(app, web) - 定期,当应用程序在前台或网页处于焦点时 带参数:engagement_time_msec
GA4 - How the number of sessions is calculated
Sessions
:在您的网站或应用程序上开始的会话数(触发了 session_start 事件)。App session timeout duration
:当应用程序移至后台时,应用程序会话开始超时,但您可以选择通过包含 extend_session 参数(值为1) 应用程序在后台时发送的事件。如果您的应用经常在后台使用(例如导航和音乐应用),这将非常有用。通过setSessionTimeoutDuration
方法更改应用会话的默认超时 30 分钟。Engaged sessions
:持续 10 秒或更长时间,或具有 1 次或更多转化事件或 2 次或更多页面浏览的会话数。
Monthly (28-day), Weekly (7-day), and Daily (1-day) Active Users
日期范围,包括相对于上一个日期范围的百分比波动。一位活跃用户在设备前台使用了一个应用程序,并记录了一个 user_engagement 事件。Daily user engagement
- 日期范围内每位用户的平均每日参与度,包括与上一个日期范围相比的百分比波动。
我对定义的看法:
根据支持性 GA4/Firebase 文档,我(重新)总结了以下每个指标的定义。非常重要的一点是,只有 唯一身份用户 才应计入每个指标(给定选定的日期范围)。不需要 UNNEST
因为我们已经在 event_name
级别查询,而不是 event_parameter
级别。
- 1 天活跃用户: 1 天 唯一 活跃用户参与在设备前台有一个应用 AND 在过去 1 天内(给定选定的日期范围)记录了一个
user_engagement
事件。 - 7 天活跃用户: 7 天 唯一 活跃用户参与在设备前台有一个应用 AND 在过去 7 天内(给定选定的日期范围)记录了一个
user_engagement
事件。 - 28 天活跃用户: 28 天 唯一 活跃用户参与在设备前台有一个应用 AND 在过去 28 天内(给定选定的日期范围)记录了一个
user_engagement
事件。
在下面的单元格中,您可以看到 12 月指标的计算方式:
计算每个指标/受众的方法:
- 使用以下公式计算特定月份的 DAU:
Average 1-day active user metric
。 - 使用以下公式计算特定月份的 WAU:
Average 7-day active user metric
。我通过对 12 月 7 日、14 日、21 日和 28 日的快照求平均值来计算的。 - 使用以下公式计算特定月份的 MAU:
Non-averaged 28-day active user metric
。不对这个指标的值进行平均的主要原因是,因为我只想获得整个月的一个快照。如果我在这里使用平均值,我也会考虑上个月的活跃用户。
1.a) 平均 1 天唯一活跃用户指标
# StandardSQL
SELECT
ROUND(AVG(users),0) AS users
FROM
(
SELECT
event_date,
COUNT(DISTINCT user_pseudo_id) AS users
FROM `<id>.events_*`
WHERE
event_name = 'user_engagement'
AND _TABLE_SUFFIX BETWEEN '20181201' AND '20181231'
AND platform = "ANDROID"
GROUP BY 1
) table
# or you could also use code below, but you will have to add in the remaining days' code to query against the entire month.
-- Set your variables here
WITH timeframe AS (SELECT DATE("2018-12-01") AS start_date, DATE("2018-12-31") AS end_date)
-- Query your variables here
SELECT ROUND(AVG(users),0) AS users
FROM
(
SELECT event_date, COUNT(DISTINCT user_pseudo_id) AS users
FROM `<id>.events_*`AS z, timeframe AS t
WHERE
event_name = 'user_engagement'
AND _TABLE_SUFFIX > FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 1 DAY))
AND _TABLE_SUFFIX <= FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL 0 DAY))
AND platform = "ANDROID"
GROUP BY 1
UNION ALL
SELECT event_date, COUNT(DISTINCT user_pseudo_id) AS users
FROM `<id>.events_*`AS z, timeframe AS t
WHERE
event_name = 'user_engagement'
AND _TABLE_SUFFIX > FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 2 DAY))
AND _TABLE_SUFFIX <= FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 1 DAY))
AND platform = "ANDROID"
GROUP BY 1
...
...
...
...
) avg_1_day_active_users
1.b) 平均 1 天唯一活跃用户指标
更新的版本计划 daily
到 BQ 目标 table daus_android_{run_time|"%Y%m%d"}
并具有写入首选项 WRITE_APPEND
,如下所示。我之前进行了深入研究,确定日内 -table 事件最多可能需要 48 小时才能传播到永久 BQ tables(因此查询中有 - 3 天)。
with base AS (
SELECT *
FROM `<id>.analytics_<number>.events_*`
WHERE (_TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 3 DAY)) AND _TABLE_SUFFIX < FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)))
AND platform = "ANDROID"
AND event_name = 'user_engagement'
), app AS (
SELECT
FORMAT_DATE('%Y%m%d', @run_date) AS _currentdate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 3 DAY)) AS _begindate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)) AS _enddate,
TIMESTAMP_DIFF(TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 2 DAY)), TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 3 DAY)), HOUR) AS _hoursdiff,
COUNT(DISTINCT user_pseudo_id) AS _uniqusers
FROM base
)
SELECT
app._currentdate,
app._begindate,
app._enddate,
app._hoursdiff,
app._uniqusers
FROM app;
1.c) 平均 1 天唯一活跃用户指标
WITH app as (
SELECT
FORMAT_DATE('%Y%m%d', @run_date) AS _currentdate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 3 DAY)) AS _begindate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)) AS _enddate,
TIMESTAMP_DIFF(TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 2 DAY)), TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 3 DAY)), HOUR) AS _hoursdiff,
COUNT(DISTINCT user_pseudo_id) AS _uniqusers
FROM `<gcp-project>.analytics_<id>.events_*`
WHERE
platform = "ANDROID"
AND event_name = 'user_engagement'
AND _TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 3 DAY))
AND _TABLE_SUFFIX < FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY))
)
SELECT
app._currentdate,
app._begindate,
app._enddate,
app._hoursdiff,
app._uniqusers
FROM app
2.a) 平均 7 天唯一活跃用户指标
-- Set your variables here
WITH timeframe AS (SELECT DATE("2018-12-01") AS start_date, DATE("2018-12-31") AS end_date)
-- Query your variables here
SELECT ROUND(AVG(users),0) AS users
FROM
(
SELECT COUNT(DISTINCT user_pseudo_id) AS users
FROM `<id>.events_*`AS z, timeframe AS t
WHERE
event_name = 'user_engagement'
AND _TABLE_SUFFIX > FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 7 DAY))
AND _TABLE_SUFFIX <= FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL 0 DAY))
AND platform = "ANDROID"
UNION ALL
SELECT COUNT(DISTINCT user_pseudo_id) AS users
FROM `<id>.events_*`AS z, timeframe AS t
WHERE
event_name = 'user_engagement'
AND _TABLE_SUFFIX > FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 14 DAY))
AND _TABLE_SUFFIX <= FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 7 DAY))
AND platform = "ANDROID"
UNION ALL
SELECT COUNT(DISTINCT user_pseudo_id) AS users
FROM `<id>.events_*`AS z, timeframe AS t
WHERE
event_name = 'user_engagement'
AND _TABLE_SUFFIX > FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 21 DAY))
AND _TABLE_SUFFIX <= FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 14 DAY))
AND platform = "ANDROID"
UNION ALL
SELECT COUNT(DISTINCT user_pseudo_id) AS users
FROM `<id>.events_*`AS z, timeframe AS t
WHERE
event_name = 'user_engagement'
AND _TABLE_SUFFIX > FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 28 DAY))
AND _TABLE_SUFFIX <= FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 21 DAY))
AND platform = "ANDROID"
) avg_7_day_active_users
2.b) 平均 7 天唯一活跃用户指标
更新的版本计划 daily
到 BQ 目标 table waus_android_{run_time|"%Y%m%d"}
,写入首选项 WRITE_APPEND
,可能看起来像:
with base AS (
SELECT *
FROM `<id>.analytics_<number>.events_*`
WHERE (_TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 9 DAY)) AND _TABLE_SUFFIX < FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)))
AND platform = "ANDROID"
AND event_name = 'user_engagement'
), app AS (
SELECT
FORMAT_DATE('%Y%m%d', @run_date) AS _currentdate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 9 DAY)) AS _begindate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)) AS _enddate,
TIMESTAMP_DIFF(TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 2 DAY)), TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 9 DAY)), HOUR) AS _hoursdiff,
COUNT(DISTINCT user_pseudo_id) AS _uniqusers
FROM base
)
SELECT
app._currentdate,
app._begindate,
app._enddate,
app._hoursdiff,
app._uniqusers
FROM app;
3.a) 非平均 28 天唯一活跃用户指标
# StandardSQL
-- Set your variables here
WITH timeframe AS (SELECT DATE("2018-12-01") AS start_date, DATE("2018-12-31") AS end_date)
-- Query your variables here
SELECT COUNT(DISTINCT user_pseudo_id) AS users
FROM `<id>.events_*`AS z, timeframe AS t
WHERE
event_name = 'user_engagement'
AND _TABLE_SUFFIX > FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL - 28 DAY))
AND _TABLE_SUFFIX <= FORMAT_DATE('%Y%m%d', DATE_ADD(t.end_date, INTERVAL 0 DAY))
AND platform = "ANDROID"
3.b) 非平均 28 天唯一活跃用户指标
更新的版本计划 daily
到 BQ 目的地 table maus_android_{run_time|"%Y%m%d"}
,写入首选项 WRITE_APPEND
,可能看起来像:
with base AS (
SELECT *
FROM `<id>.analytics_<number>.events_*`
WHERE (_TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 30 DAY)) AND _TABLE_SUFFIX < FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)))
AND platform = "ANDROID"
AND event_name = 'user_engagement'
), app AS (
SELECT
FORMAT_DATE('%Y%m%d', @run_date) AS _currentdate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 30 DAY)) AS _begindate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)) AS _enddate,
TIMESTAMP_DIFF(TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 2 DAY)), TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 30 DAY)), HOUR) AS _hoursdiff,
COUNT(DISTINCT user_pseudo_id) AS _uniqusers
FROM base
)
SELECT
app._currentdate,
app._begindate,
app._enddate,
app._hoursdiff,
app._uniqusers
FROM app;
旁注:
- 我知道有些公司仍在计算他们 30 天的 MAU。因此,您必须进行测试,看看哪种方法最适合您的公司。
- 您可以根据上述示例计算自己的
DAU-to-MAU
比率或WAU-to-MAU
比率,以确定您应用的 stickiness - 我对 MAU 计算的唯一问题是它还没有考虑每个月的开始日期。也许可以取第 31 天 - 28 天、第 30 天 - 28 天、第 29 天 - 28 天、第 28 天 - 28 天的平均值 ...
- 我发现 Firebase 团队的示例 queries 也很有帮助,但他们的活跃指标仅涉及执行查询时的活跃用户数(查看下面的示例):
SELECT COUNT(DISTINCT user_id) FROM /* PLEASE REPLACE WITH YOUR TABLE NAME */ `YOUR_TABLE.events_*` WHERE event_name = 'user_engagement' /* Pick events in the last N = 20 days */ AND event_timestamp > UNIX_MICROS(TIMESTAMP_SUB(CURRENT_TIMESTAMP, INTERVAL 20 DAY)) /* PLEASE REPLACE WITH YOUR DESIRED DATE RANGE */ AND _TABLE_SUFFIX BETWEEN '20180521' AND '20240131';
忍者秘诀
要将您的团队“s/company”s/product 的关注点从 Vanity Metrics
转移到 Actionable Metrics
,请考虑将您的主要转化事件之一添加为上面的查询(例如 in_app_purchase
for e-commerce companies):
with base AS (
SELECT *
FROM `<id>.analytics_<number>.events_*`
WHERE (_TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 3 DAY)) AND _TABLE_SUFFIX < FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)))
AND platform = "ANDROID"
# AND event_name = 'user_engagement'
AND event_name = 'in_app_purchase'
), app AS (
SELECT
FORMAT_DATE('%Y%m%d', @run_date) AS _currentdate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 3 DAY)) AS _begindate,
FORMAT_DATE('%Y%m%d', DATE_ADD(@run_date, INTERVAL - 2 DAY)) AS _enddate,
TIMESTAMP_DIFF(TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 2 DAY)), TIMESTAMP(DATE_ADD(@run_date, INTERVAL - 3 DAY)), HOUR) AS _hoursdiff,
COUNT(DISTINCT user_pseudo_id) AS _uniqusers
FROM base
)
SELECT
app._currentdate,
app._begindate,
app._enddate,
app._hoursdiff,
app._uniqusers
FROM app;