【问题标题】:Calculating average for two variables计算两个变量的平均值
【发布时间】:2014-04-04 20:25:31
【问题描述】:

我有一张如下表:

VisitorID   Product         VisitDayBeforePurchase
1           Product1            0
2           Product2            1
3           Product3            2
1           Product1            2
3           Product2            2
3           Product3            2

VisitorID 对于每个访问者来说始终是唯一的,visitDayBeforePurchase 表示他们是否在购买前 x 天来到网站。我想做的是制作一个可以将表格转换成这样的语句。

 Product   Day0   Day1  Day2
 Product1   1      0     1
 Product2   0      1     2
 Product3   0      0     2

基本上,我想查看某人在购买特定产品前 X 天访问网站的平均访问次数。即访问前每天每个产品的总和(访问)/总和(唯一访问者)

我正打算从表 1 中下载数据并编写一个脚本来计算它,但我想知道是否有一种方法可以在 SQL 中执行此操作。

如果有人能指出正确的方向,将不胜感激。

【问题讨论】:

  • 你用的是什么数据库?
  • 购买前是否有最大天数?像 0、1 和 2 或者它可以无限天数添加到右侧作为新列?
  • 我会说最多 30 天..我正在使用 Teradata

标签: sql teradata


【解决方案1】:

对于您描述的表格的已知列数 - 实际上不是平均值,它是一个计数 - 可以使用IF 完成:

SELECT Product,
       SUM(IF(VisitDayBeforePurchase = 0, 1, 0)) AS Day0,
       SUM(IF(VisitDayBeforePurchase = 1, 1, 0)) AS Day1,
       SUM(IF(VisitDayBeforePurchase = 2, 1, 0)) AS Day2
FROM yourtable
GROUP BY Product;

基本上,我想查看某人在购买特定产品前 X 天访问网站的平均访问次数。即访问前每天每个产品的总和(访问)/总和(唯一访问者)

这是一个不同的请求。您可以通过添加(或替换)一列来做到这一点

SELECT Product,
       AVG(VisitDayBeforePurchase) AS AverageDays
FROM yourtable
GROUP BY Product;

这给了你一切(你可以在行动中看到它here)。

SELECT Product,
       SUM(IF(VisitDayBeforePurchase = 0, 1, 0)) AS Day0,
       SUM(IF(VisitDayBeforePurchase = 1, 1, 0)) AS Day1,
       SUM(IF(VisitDayBeforePurchase = 2, 1, 0)) AS Day2,
       AVG(VisitDayBeforePurchase) AS AverageDays
FROM yourtable
GROUP BY Product;

计算多个访问者

简而言之:这很复杂,也许最好不要这样做

假设我们有一个产品被同一访问者查看两次(或更多),那么我们不想将这些视为单独的访问。如果先生。 X访问了网站三天,两天,购买当天,我们怎么办?

乍一看,我们可能会认为只计算最后次访问。但是我们会得到一个明显的意想不到的后果:由于您必须访问该网站才能在该网站上购买商品,那么购买之前的最后一次访问是您进行购买的访问,因此在购买之前总是零天。在同一小时和一分钟内,甚至,可能。虽然可以考虑上次访问,但它会给我们带来毫无价值的结果。

考虑到第一次访问也会产生忽略重复购买的意外后果,因此我们的最佳重复客户实际上会被认为是最虚伪和优柔寡断的。

因此,例如,只需要考虑实际使用 SUM 制表的天数,然后然后做一些事情:

VisitorID       ProductID       VDBeforeP
42              137             3
42              137             2
41              137             2

但是怎么办呢?如果我们只考虑访问者 42 的 一个 记录,无论我们做什么我们最终都会得到一个不正确的结果,要么平均而言过于乐观,要么平均而言过于悲观。我们可以考虑用户 42 的 average,对于权重 one(而不是 two)的用户 42,它给出了 2.5,因此与“brute平均”(上面的解决方案)我们有点少考虑重复客户。

为此,我们使用SUBSELECT:我们获得每个数据点只有一个访客和产品的平均数据

SELECT VisitorID, Product, AVG(VisitDayBeforePurchase) AS VisitDayBeforePurchase
    FROM visits GROUP BY VisitorID, Product;

这将生成一个与原始表格格式相同但包含平均数据的表格。 而且它永远不会起作用,因为原始查询只验证了 整数 天数,而 2.5 既不是 2 也不是 3。所以我们必须做出乐观或悲观的修正;这是乐观的

SELECT VisitorID, Product, FLOOR(AVG(VisitDayBeforePurchase)) AS VisitDayBeforePurchase
    FROM visits GROUP BY VisitorID, Product;

而悲观者会使用FLOOR(1.0+AVG...。折衷方案是使用ROUND

现在我们重复查询:

SELECT Product,
    SUM(IF(V = 0, 1, 0)) AS Day0,
    SUM(IF(V = 1, 1, 0)) AS Day1,
    SUM(IF(V = 2, 1, 0)) AS Day2,
    AVG(BetterV) AS AverageDays
FROM (
    SELECT VisitorID,
           Product,
           ROUND(AVG(VisitDayBeforePurchase)) AS V,
           AVG(VisitDayBeforePurchase) AS BetterV
    FROM visits GROUP BY VisitorID, Product
) AS grouped
  GROUP BY Product;

A working example can be also found here

Map-Reduce

要在 map-reduce 环境中运行上述操作,您需要两个阶段:一个直接输出 VisitorID、Product 和 VisitDayBeforePurchase 的 map 阶段,以及一个通过键(VisitorID、Product)分组并输出这些和 V 的 reduce 阶段(还有 BetterV?)计算结果。

这被馈送到一个新的 reduce 阶段,该阶段对 V 执行平均。

【讨论】:

  • 我尝试将语句修改为SUM(IF(VisitDayBeforePurchase = 0, 1, 0)) / COUNT(DISTINCT(VisitorID)) AS Day0, 以获得平均值,但出现错误
  • 所以,我希望将 VisitDayBeforePurchase 的总和除以每天的 COUNT(DISTINCT(VistorID))。这样我就可以查看产品在购买前 x 天获得的平均浏览量。
  • 我不能说我已经理解你想要达到的目标。我正在尝试修改答案以考虑到不同的访问量,但这种方法存在问题。
  • 标准 SQL/Teradata 中没有 IF,您应该使用 SUM(CASE WHEN VisitDayBeforePurchase = 0 THEN 1 ELSE 0 END)
  • 感谢伊塞尔尼的回答。查询背后的想法是检查每种产品的购买渠道。例如,报告可能显示访问者在购买前两周开始研究产品 1,而产品 2 仅在购买的同一天被查看。因此,基本上对于每种产品,我想查看过去 30 天的情况,看看是否有任何有趣的浏览/研究模式——这些信息可用于帮助营销工作。
猜你喜欢
  • 1970-01-01
  • 2016-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-03
  • 2017-02-06
  • 2015-02-23
相关资源
最近更新 更多