2009-09-10 8 views
5

den Stack-Überlauf öffentliche Daten-Dump verwenden, habe ich drei einfache Tabellen erstellt:Approximierende Seitenansichten pro Tag (oder Tag-Gruppe) pro Monat mit begrenzten Daten?

  • Fragen (Question_Id, VIEW_COUNT, creation_date)
  • Schlagworte (Tag_Name)
  • QuestionTags (Question_Id, Tag_Name)

Die Questions-Tabelle hat Hunderttausende von Zeilen mit Creation_Date von einem Jahr bis heute. Mit Blick auf den Daten gibt es zwei bemerkenswerte Trends:

  • Anzahl der Fragen Periodisches erhöhen - zum Beispiel, gibt es mehr Fragen in diesem Monat wurden gebeten, als vor drei Monaten
  • Fragen Ansichten haben eine Long Tail - Durch das Betrachten von Ansichten basierend auf offenen Wochen können wir sehen, dass die meisten Fragen einer Frage in der ersten Woche auftreten; eine geringere Menge in der zweiten und dritten; und ein langer, konstanter Schwanz in den folgenden Wochen

Wenn keiner dieser Faktoren kam zu spielen, wäre es ziemlich trivial Verkehr für einen bestimmten Tag zu schätzen (oder eine Gruppe von Tags) über einen Monat:

SELECT YEAR(Q.Creation_Date) 
     ,MONTH(Q.Creation_Date) 
     ,SUM(Q.View_Count/DATEDIFF(m,Q.Creation_Date,GETDATE())) 
    FROM Questions Q 
     JOIN QuestionTags QT 
     ON Q.Question_Id = QT.Question_Id 
WHERE QT.Tag_Name IN ('c#','.net', ...) 
GROUP BY YEAR(Q.Creation_Date), MONTH(Q.Creation_Date) 
ORDER BY 1,2 

Aber wegen der oben genannten Faktoren (vor allem der lange Schwanz), bin ich mir nicht sicher, wie man Ansichten annähert. Meine Gedanken sind, eine Funktion zu erstellen, die mithilfe der Long-Tail-Formel Ansichten für einen Monat basierend auf der aktuellen Anzahl von Ansichten und offenen Wochen berechnet.

Hier ist, was ich kam mit dem Schwanz zu finden:

DECLARE @SDTE DATETIME, @EDTE DATETIME 
SELECT @SDTE = '2009-01-11' -- after new years holiday 
     ,@EDTE = CAST(MAX([Creation_Date]) AS INT) 
    FROM [Questions] 


SELECT [DaysOpen_Count] 
     ,AVG([WView_Count]) 
     FROM 
    (
    SELECT QT.[Tag_Name], 
     Q.[View_Count], 
     [DaysOpen_Count] = DATEDIFF(DAY, Q.[Creation_Date], @EDTE), 
     [WView_Count] = CAST(Q.[View_Count]/(DATEDIFF(DAY, Q.[Creation_Date], @EDTE)/7.0) AS INT) 
    FROM [Questions] Q 
     INNER JOIN [QuestionTags] QT 
     ON Q.[Question_Id] = QT.[Question_Id] 
    WHERE [Tag_Name] IN ('c#','.net',...) 
    AND [Creation_Date] < @EDTE 
) Q 
GROUP BY [DaysOpen_Count] 
ORDER BY 1,2 

Wie soll ich diese SQL-Abfrage zu erstellen, gehen Sie?

Das Endziel ist ein Stored Procedure, das eine CSV-Zeichenfolge aus Tags eingibt und die Seitenaufrufe der letzten sechs Monate für diese Tags ausspuckt.

UPDATE Nachdem ich das Tumbleweed-Abzeichen "verdient" hatte, dachte ich, es wäre Zeit für ein Kopfgeld!

Antwort

5

Sie benötigen eine exponentielle Ansichten Abklingkurve, etwas Ähnliches wie dies zu berücksichtigen - http://en.wikipedia.org/wiki/Exponential_decay

Was brauchen wir hier ist die Fläche unter der Kurve bis gewünschte Zeit (in Tagen).

Wenn Sie die Mathematik zu tun, werden Sie zu einem Ergebnis kommen

Views = V/λ[1 - e^(-λt)] 

t (Datum erstellt - das heutige Datum - 1)

V ist die Ansicht Zahl haben wir

λ kann 2ln2/T oder 1,4/T sein

T kann eine große Lebensdauer wie 5 Tage oder 7 Tage sein. Nehmen wir es 5.

Wir machen viele Annahmen hier wegen der dynamischen Natur von SO. Aber ich bin überzeugt, dass es schöne Ergebnisse liefert.

Alles, was Sie jetzt tun müssen, ist die entsprechenden Werte zu ersetzen und Ansichten zu erhalten.

+0

Das sieht sehr genau aus, wonach ich gesucht habe; Was die dynamische Natur anbelangt ... alles wird gemittelt, besonders wenn wir die "Freak" -Fragen wie http: // stackoverflow fallen lassen.com/questions/84556/whats-your-liebling-programmierer-cartoon –

+0

Möglicherweise müssen Sie die Formel, insbesondere die V und Abklingrate λ Feinabstimmung. Decay Rate für solche Fragen ist sehr niedrig (1/25?). –

2

Ich dachte, dieses Verfahren für den Schwanz Schätzung:

für eine Liste von Tags, für jede Frage in dieser Tags dem ersten Monat nach creation_date 80% der VIEW_COUNT dem zweiten Monat nach creation_date geben geben 10 % of View_Count Split 10% gleichmäßig zwischen den verbleibenden Monaten bis heute

natürlich 80%, 10% ist nur eine meiner Wahl, sie können genauer auf der Grundlage echter Daten berechnet werden. Auch der zweite Monat 10% kann eliminiert werden. All diese Logik ist im: CASE WHEN diff ... Teil.

Sie obtain geschätzte view_count/question/Monat

dann alles, was Sie tun müssen, ist die Summe view_count pro Monat und wenn Sie eine Bedingung für den Monat

ein Zeitfenster hinzufügen möchten Ich habe eine gespeicherte Prozedur das kann dies tun, aber Sie müssen zuerst eine temporäre Tabelle #tags (Tag_name) erstellen, in die Sie die gewünschten Tags einfügen.

CREATE PROCEDURE GetTagViews @startDate datetime, @endDate datetime 
As 

IF exists (SELECT null FROM sysobjects WHERE name = '#months' and type = 'U') 
    DROP TABLE #MONTHS 

CREATE TABLE #MONTHS 
(
    month datetime 
) 

DECLARE @currMonth datetime 
SELECT @currMonth = MIN(Creation_Date) FROM Questions 

-- Populate #MONTHS with all the months from the oldest 
-- question creation_date to Today 
WHILE @currMonth < getdate() 
BEGIN 
    -- insert date starting at the beginning og the month 
    INSERT INTO #MONTHS select @currMonth - day(@currMonth) + 1 
    SELECT @currMonth = dateadd(m, 1, @currMonth) -- advance 1 month 
END 

SELECT YEAR(month) y, MONTH(month) m, SUM(curr_month_views) Views FROM (
SELECT Q1.month, Q1.diff, round(
CASE WHEN diff = dmin and diff = dmax THEN View_Count 
    WHEN diff = dmin and diff < dmax THEN 0.8*View_Count 
    WHEN diff = dmin+1 and diff < dmax THEN 0.1*View_Count 
    WHEN diff = dmin+1 and diff = dmax THEN 0.2*View_Count 
    WHEN diff >= dmin+2 THEN 0.1/(dmax - (dmin+2) + 1)*View_Count 
    ELSE 0 
END, 0) curr_month_views 
FROM (
SELECT Q.question_id, m.month, 
    DATEDIFF(m, Q.Creation_Date, m.month) diff, 
    Q.View_Count, dmin, dmax 
FROM Questions Q, 
    #MONTHS m, 
    (SELECT MIN(DATEDIFF(m, Q.Creation_Date, m.month)) [dmin], 
      MAX(DATEDIFF(m, Q.Creation_Date, m.month)) [dmax] 
     FROM Questions Q,#MONTHS m 
     WHERE DATEDIFF(m, Q.Creation_Date, m.month) >= 0) MINMAX 
) Q1 join QuestionTags QT on Q1.question_id = QT.question_id 
    join #tags on #tags.Tag_Name = QT.Tag_Name 
) b WHERE month >= @startDate - day(@startDate) + 1 
     AND month <= @enddate - day(@enddate) + 1 
GROUP BY Year(month), Month(month) 
ORDER BY 1, 2 

Wenn ich laufen diese Prozedur mit den folgenden Daten:

Question_Id View_Count Creation_Date     tag_name   
----------- ----------- ------------------------------ ---------- 
0   42   2009-09-10 00:00:00.000  sql 
1   326   2008-08-04 00:00:00.000  sql 
2   377   2008-08-04 00:00:00.000  sql 
3   568   2008-08-03 00:00:00.000  sql 
4   839   2008-08-01 00:00:00.000  sql 
5   228   2009-03-01 00:00:00.000  sql 
6   178   2009-03-11 00:00:00.000  sql 
7   348   2009-08-11 00:00:00.000  c# 

bevölkern #tags mit 'SQL'

GetTagViews '20090501', '20091001' 

    y   m   Views          
    ----------- ----------- --------------- 
    2009  5   21.000000000000 
    2009  6   21.000000000000 
    2009  7   21.000000000000 
    2009  8   21.000000000000 
    2009  9   55.000000000000 

bevölkern #tags mit 'C#'

GetTagViews '20090501', '20091001' 

    y   m   Views          
    ----------- ----------- ---------------------------------------- 
    2009  5   .000000000000 
    2009  6   .000000000000 
    2009  7   .000000000000 
    2009  8   278.000000000000 
    2009  9   35.000000000000 

befüllen #Tags mit beiden 'sql' & 'C#'

GetTagViews '20090501', '20091001' 

    y   m   Views          
    ----------- ----------- ---------------- 
    2009  5   21.000000000000 
    2009  6   21.000000000000 
    2009  7   21.000000000000 
    2009  8   299.000000000000 
    2009  9   90.000000000000 

(Sie, dass Peak für (SQL, C# siehe Vergleich) nur (SQL) für 2009-08, ist es aufgrund der C# Frage in diesem Monat gefragt.)

NB : Das Rouding von Schätzungen führt zu einem Unterschied einiger Ansichten (~ 1), wenn Sie detaillierte Ansichten zusammenfassen und mit den ursprünglichen Daten für eine gegebene Frage vergleichen!

+0

dies ist sehr schön, dank; Ich werde es versuchen –

0

Um lange Schwänze nachzubilden, führen Sie einfach eine Konstante ein. Oder logarithmische Funktion verwenden.

your_formula(delta_t) + C 

1/(1 + log(1 + delta_t)) 

(Koeffizienten weggelassen)

Verwandte Themen