2014-04-04 80 views
1

计算平均我有一个表像如下:两个变量

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天访问网站的平均访问次数。即访问前每天每个产品的总和(访问次数)/总和(uniqueVisitors)

我只是要从表1下载数据并编写一个脚本来计算这一点,但我想知道是否有办法做这在SQL中。

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

+0

你使用的数据库是? –

+0

购买前是否有最长的天数?如0,1和2,或者可以将无限期天数添加到右侧作为新列? – Prix

+0

我会说最多30天..我使用Teradata – cloud36

回答

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三天两天访问该网站,在购买当天,我们该怎么办?

乍一看,我们可能认为只计算了最近的访问。但是我们会得到一个明显的意外后果:因为您必须访问该网站才能购买该网站上的项目,那么最后访问之前购买是访问,因此您购买,所以它将永远是购买之前的零天。在相同的小时和分钟,甚至可能。虽然有可能考虑上次访问,但这会给我们带来无价值的结果。

考虑第一访问还有一个能够眺望重复购买的意想不到的后果,使我们的最好重复的客户实际上将被视为是最diddling和优柔寡断。

所以一个人必须要考虑的,例如,仅一天的时间间隔实际上SUM表格,并然后做一些事情:

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

做什么?如果我们只考虑一个记录访客42,我们做什么我们最终得到的结果不正确,平均过于乐观或平均过于悲观。我们可以考虑用户42的平均,这给2.5用户42重量(而不是)一个,所以在用“蛮力平均”比较(上解),我们那种认为回头客少一点。

要做到这一点,我们使用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

要在地图,减少环境中运行上面的你就需要两个阶段:一个地图阶段直接输出VisitorID,Product和VisitDayBeforePurchase,以及一个按关键字(VisitorID,Product)分组的reduce阶段,并输出这些和V(和BetterV?)计算结果。

这得到了一个新的减少阶段,执行V的平均值。

+0

我试图修改语句为SUM(IF(VisitDayBeforePurchase = 0,1,0))/ COUNT(DISTINCT(VisitorID))AS Day0,'为了得到平均值,但得到了一个错误 – cloud36

+0

因此,我期待每天将COUNT(DISTINCT(VistorID))除以VisitDayBeforePurchase的总和。这样,我可以看到产品在购买前x天的平均观看量。 – cloud36

+1

我不能说我已经理解你想要达到的目标。我试图修改答案,以考虑到不同的访问者的事情,但这种方法有问题。 – LSerni