2014-04-04 116 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