如何计算bigquery中的每月留存用户?
How to count monthly retention user in bigquery?
我有如下原始数据。每行是用户的一笔交易记录,以及他们进行交易的月份
我想要的是计算一个月内下单的用户数和上个月的重复用户数(RETENTION),然后我可以知道有多少用户是重复用户。
期望的结果应该是这样的
如何在 bigquery 中实现?
实现它的一种方法是通过具有相同 table 和 1 个月延迟的自加入。这样,我们将 user&month 组合与 user&previous-month 进行匹配,以查看它是否是回头客。例如,使用 2M 行 public table bigquery-public-data.hacker_news.stories
和特定用户:
请注意,对于 2014-02-01,prev_month
为 null(我们使用 LEFT OUTER JOIN
)该用户在 2014-01-01 期间 未 活跃。我们正在加入作者并滞后几个月:
FROM authors AS a
LEFT OUTER JOIN authors AS b
ON a.author = b.author
AND a.month = DATE_ADD(b.month, INTERVAL 1 MONTH)
然后如果上个月不为空,我们将用户计为重复用户:
COUNT(a.author) AS num_users,
COUNTIF(b.month IS NOT NULL) AS num_returning_users
请注意,我们在这里不使用 DISTINCT
,因为我们在将 orders
定义为 CTE 时已经按作者和月份组合分组。对于其他示例,您可能需要考虑到这一点。
完整查询:
WITH
authors AS (
SELECT
author,
DATE_TRUNC(DATE(time_ts), MONTH) AS month
FROM
`bigquery-public-data.hacker_news.stories`
WHERE
author IS NOT NULL
GROUP BY 1,2)
SELECT
*,
ROUND(100*SAFE_DIVIDE(num_returning_users,
num_users),2) AS retention
FROM (
SELECT
a.month,
COUNT(a.author) AS num_users,
COUNTIF(b.month IS NOT NULL) AS num_returning_users
FROM
authors AS a
LEFT OUTER JOIN
authors AS b
ON
a.author = b.author
AND a.month = DATE_ADD(b.month, INTERVAL 1 MONTH)
GROUP BY 1
ORDER BY 1
LIMIT 100)
和结果片段:
哪些是正确的结果,即 2007-03-01
:
性能并不太花哨,但在这种情况下,我们仅选择聚合数据所需的字段,因此扫描数据较少且执行时间不会太长(~5 秒)。
另一种方法是在 COUNTIF()
中使用 EXISTS()
而不是连接
但对我来说需要更长的时间(~7s)。 Query
如果您只是查看上个月,请执行以下操作:
- 将月份转换为数字。
- 在 user/month 级别聚合数据。
那么你可以直接使用lag()
:
select month,
count(*) as num_users,
countif(prev_month_int = month_int - 1) as prev_num_users,
countif(prev_month_int = month_int - 1) / count(*) as repeat_rate
from (select mu.*,
lag(month_int) over (partition by userid order by month_int) as prev_month_int
from (select month, userid, count(*) as num_orders,
cast(split(month, '-')[ordinal(1)] as int64) * 12 + cast(split(month, '-')[ordinal(2)] as int64) as month_int
from t
group by month, userid
) mu
) mu
group by month;
我有如下原始数据。每行是用户的一笔交易记录,以及他们进行交易的月份
我想要的是计算一个月内下单的用户数和上个月的重复用户数(RETENTION),然后我可以知道有多少用户是重复用户。
期望的结果应该是这样的
如何在 bigquery 中实现?
实现它的一种方法是通过具有相同 table 和 1 个月延迟的自加入。这样,我们将 user&month 组合与 user&previous-month 进行匹配,以查看它是否是回头客。例如,使用 2M 行 public table bigquery-public-data.hacker_news.stories
和特定用户:
请注意,对于 2014-02-01,prev_month
为 null(我们使用 LEFT OUTER JOIN
)该用户在 2014-01-01 期间 未 活跃。我们正在加入作者并滞后几个月:
FROM authors AS a
LEFT OUTER JOIN authors AS b
ON a.author = b.author
AND a.month = DATE_ADD(b.month, INTERVAL 1 MONTH)
然后如果上个月不为空,我们将用户计为重复用户:
COUNT(a.author) AS num_users,
COUNTIF(b.month IS NOT NULL) AS num_returning_users
请注意,我们在这里不使用 DISTINCT
,因为我们在将 orders
定义为 CTE 时已经按作者和月份组合分组。对于其他示例,您可能需要考虑到这一点。
完整查询:
WITH
authors AS (
SELECT
author,
DATE_TRUNC(DATE(time_ts), MONTH) AS month
FROM
`bigquery-public-data.hacker_news.stories`
WHERE
author IS NOT NULL
GROUP BY 1,2)
SELECT
*,
ROUND(100*SAFE_DIVIDE(num_returning_users,
num_users),2) AS retention
FROM (
SELECT
a.month,
COUNT(a.author) AS num_users,
COUNTIF(b.month IS NOT NULL) AS num_returning_users
FROM
authors AS a
LEFT OUTER JOIN
authors AS b
ON
a.author = b.author
AND a.month = DATE_ADD(b.month, INTERVAL 1 MONTH)
GROUP BY 1
ORDER BY 1
LIMIT 100)
和结果片段:
哪些是正确的结果,即 2007-03-01
:
性能并不太花哨,但在这种情况下,我们仅选择聚合数据所需的字段,因此扫描数据较少且执行时间不会太长(~5 秒)。
另一种方法是在 COUNTIF()
中使用 EXISTS()
而不是连接
但对我来说需要更长的时间(~7s)。 Query
如果您只是查看上个月,请执行以下操作:
- 将月份转换为数字。
- 在 user/month 级别聚合数据。
那么你可以直接使用lag()
:
select month,
count(*) as num_users,
countif(prev_month_int = month_int - 1) as prev_num_users,
countif(prev_month_int = month_int - 1) / count(*) as repeat_rate
from (select mu.*,
lag(month_int) over (partition by userid order by month_int) as prev_month_int
from (select month, userid, count(*) as num_orders,
cast(split(month, '-')[ordinal(1)] as int64) * 12 + cast(split(month, '-')[ordinal(2)] as int64) as month_int
from t
group by month, userid
) mu
) mu
group by month;