过去 30 天的移动平均线

Posted

技术标签:

【中文标题】过去 30 天的移动平均线【英文标题】:Moving average last 30 days 【发布时间】:2018-06-07 08:39:12 【问题描述】:

我想查找过去 30 天内活跃的唯一身份用户数。我想为今天计算这个,也为过去的几天计算。该数据集包含保存在 BigQuery 中的用户触发的用户 ID、日期和事件。用户通过打开触发事件 session_start 的移动应用程序处于活动状态。未嵌套数据集的示例。

| resettable_device_id |     date    |    event      |
------------------------------------------------------
|         xx           |  2017-06-09 | session_start |
|         yy           |  2017-06-09 | session_start |
|         xx           |  2017-06-11 | session_start |
|         zz           |  2017-06-11 | session_start |

我找到了适合我的问题的解决方案: BigQuery: how to group and count rows within rolling timestamp window?

到目前为止我的 BigQuery 脚本:

#standardSQL
WITH daily_aggregation AS (
  SELECT 
    PARSE_DATE("%Y%m%d", event_dim.date) AS day,
    COUNT(DISTINCT user_dim.device_info.resettable_device_id) AS unique_resettable_device_ids
  FROM `android.app_events_*`,
    UNNEST(event_dim) AS event_dim
  WHERE event_dim.name = "session_start"
  GROUP BY day
)
SELECT 
  day, 
  unique_resettable_device_ids, 
  SUM(unique_resettable_device_ids) 
  OVER(ORDER BY UNIX_SECONDS(TIMESTAMP(day)) DESC ROWS BETWEEN 2592000 PRECEDING AND CURRENT ROW) AS unique_ids_rolling_30_days
FROM daily_aggregation
ORDER BY day

此脚本生成下表:

|      day   | unique_resettable_device_ids | unique_ids_rolling_30_days |
------------------------------------------------------------------------
| 2018-06-05 |            1807              |            2614            |
| 2018-06-06 |             711              |             807            |
| 2018-06-07 |              96              |              96            |

问题在于 unique_ids_rolling_30_days 列只是 unique_resettable_device_ids 列的累积和。如何修复脚本中的滚动窗口功能?

【问题讨论】:

您可以将您的解决方案添加为答案并自行接受。这对于找到这个问题的人来说会更清楚。 从原始问题中删除了解决方案并将其添加为答案。 【参考方案1】:

“问题在于 unique_ids_rolling_30_days 列只是 unique_resettable_device_ids 列的累积和。”

当然,代码就是这样

SUM(unique_resettable_device_ids) OVER(ORDER BY UNIX_SECONDS(TIMESTAMP(day)) DESC ROWS BETWEEN 2592000 PRECEDING AND CURRENT ROW) AS unique_ids_rolling_30_days

正在请求。

查看https://***.com/a/49866033/132438,该问题询问有关在滚动窗口中专门计算唯一性的问题:事实证明,考虑到它需要多少内存,这是一个非常缓慢的操作。

当您需要滚动计数唯一性时的解决方案:获取近似结果。

来自链接的答案:

#standardSQL
SELECT DATE_SUB(date, INTERVAL i DAY) date_grp
 , HLL_COUNT.MERGE(sketch) unique_90_day_users
 , HLL_COUNT.MERGE(DISTINCT IF(i<31,sketch,null)) unique_30_day_users
 , HLL_COUNT.MERGE(DISTINCT IF(i<8,sketch,null)) unique_7_day_users
 , COUNT(*) window_days
FROM (
  SELECT DATE(creation_date) date, HLL_COUNT.INIT(owner_user_id) sketch
  FROM `bigquery-public-data.***.posts_questions` 
  WHERE EXTRACT(YEAR FROM creation_date)=2017
  GROUP BY 1
), UNNEST(GENERATE_ARRAY(1, 90)) i
GROUP BY 1
HAVING window_days=90
ORDER BY date_grp

【讨论】:

感谢您的回复。我将您的代码转换为我的用例,但脚本的结果与验证脚本不匹配。我的验证脚本只是从今天到过去 30 天的一个窗口中的活跃用户数。有人帮我找到了另一个解决方案,您可以在我更新的帖子中找到。 对不起,我添加了解决方案。它现在每周计算活跃用户数。【参考方案2】:

在过去 30 天内每周计算活跃用户数的有效解决方案。

#standardSQL
WITH days AS (
  SELECT day 
  FROM UNNEST(GENERATE_DATE_ARRAY('2018-01-01', CURRENT_DATE(), INTERVAL 1 WEEK)) AS day
), periods AS (
SELECT 
  DATE_SUB(days.day, INTERVAL 30 DAY) AS StartDate,
  days.day AS EndDate FROM days
)
SELECT
  periods.EndDate AS Day,
  COUNT(DISTINCT user_dim.device_info.resettable_device_id) as resettable_device_ids
FROM `ANDROID.app_events_*`,
  UNNEST(event_dim) AS event_dim
CROSS JOIN periods
WHERE
  PARSE_DATE("%Y%m%d", event_dim.date) BETWEEN periods.StartDate AND periods.EndDate
  AND event_dim.name = "session_start"
GROUP BY Day
ORDER BY Day DESC

【讨论】:

以上是关于过去 30 天的移动平均线的主要内容,如果未能解决你的问题,请参考以下文章

如何将现实世界 5 天的每日股票数据转换为每周模式以获得每周移动平均线

mysql 在过去 N 小时内的简单移动平均线

量化交易——双均线策略(金叉死叉)

在 bigquery 中计算 7、14 和 30 天移动平均线

熊猫移动平均线[重复]

Oracle SQL 查询移动平均线