Qual è il modo migliore per calcolare argomenti o tag di tendenza?


183

Molti siti offrono alcune statistiche come "Gli argomenti più caldi nelle ultime 24 ore". Ad esempio, Topix.com lo mostra nella sua sezione "Tendenze delle notizie". Qui puoi vedere gli argomenti che hanno il numero di menzioni in più rapida crescita.

Voglio calcolare un simile "ronzio" anche per un argomento. Come potrei farlo? L'algoritmo dovrebbe ponderare gli argomenti che sono sempre più caldi. Gli argomenti che normalmente (quasi) nessuno menziona dovrebbero essere i più caldi.

Google offre "Hot Trends", topix.com mostra "Hot Topics", fav.or.it mostra "Keyword Trends" - tutti questi servizi hanno una cosa in comune: mostrano solo le tendenze imminenti che sono anormalmente calde al momento.

Termini come "Britney Spears", "meteo" o "Paris Hilton" non compariranno in questi elenchi perché sono sempre caldi e frequenti. Questo articolo chiama questo "The Britney Spears Problem".

La mia domanda: come si può programmare un algoritmo o utilizzarne uno esistente per risolvere questo problema? Avendo un elenco con le parole chiave cercate nelle ultime 24 ore, l'algoritmo dovrebbe mostrarti le 10 (ad esempio) più calde.

So che, nell'articolo sopra, c'è un qualche tipo di algoritmo menzionato. Ho provato a codificarlo in PHP ma non credo che funzionerà. Trova solo la maggioranza, no?

Spero che tu mi possa aiutare (esempi di codifica sarebbero fantastici).


4
Domanda interessante, curiosa di vedere cosa hanno da dire le persone.
mmcdole,

14
Nessun motivo per chiudere, questa è una domanda valida
TStamper

1
Questa è esattamente la stessa domanda e lo afferma persino! Perché le persone lo votano!
Darryl Hein,

3
Sono un po 'confuso riguardo al tipo di risultato che stai cercando. L'articolo sembra indicare che "Britney Spears" sarà costantemente trovato nell'elenco "Hot" perché così tante persone cercano quel termine, ma la tua domanda afferma che NON comparirà nell'elenco perché il numero di ricerche per quel termine lo fanno non aumentano molto nel tempo (rimangono alti, ma costanti). Quale risultato stai cercando di ottenere? "Britney Spears" dovrebbe essere alto o basso?
e.James,

1
@eJames, "Britney Spears" non dovrebbe essere alto perché è costantemente un termine di ricerca elevato e sta cercando termini di ricerca ad alta velocità.
mmcdole,

Risposte:


103

Questo problema richiede un punteggio z o un punteggio standard, che terrà conto della media storica, come altri hanno già detto, ma anche della deviazione standard di questi dati storici, rendendola più robusta rispetto al semplice utilizzo della media.

Nel tuo caso, un punteggio z viene calcolato con la formula seguente, in cui la tendenza sarebbe una frequenza come visualizzazioni / giorno.

z-score = ([current trend] - [average historic trends]) / [standard deviation of historic trends]

Quando viene utilizzato un punteggio z, più alto o più basso è il punteggio z, più anomala è la tendenza, quindi ad esempio se il punteggio z è altamente positivo, la tendenza aumenta in modo anormale, mentre se è altamente negativa diminuisce in modo anomalo . Quindi, una volta calcolato il punteggio z per tutte le tendenze candidate, i 10 punteggi z più alti si collegheranno ai punteggi z che aumentano in modo anomalo.

Per ulteriori informazioni, consultare Wikipedia , sui punteggi z.

Codice

from math import sqrt

def zscore(obs, pop):
    # Size of population.
    number = float(len(pop))
    # Average population value.
    avg = sum(pop) / number
    # Standard deviation of population.
    std = sqrt(sum(((c - avg) ** 2) for c in pop) / number)
    # Zscore Calculation.
    return (obs - avg) / std

Uscita campione

>>> zscore(12, [2, 4, 4, 4, 5, 5, 7, 9])
3.5
>>> zscore(20, [21, 22, 19, 18, 17, 22, 20, 20])
0.0739221270955
>>> zscore(20, [21, 22, 19, 18, 17, 22, 20, 20, 1, 2, 3, 1, 2, 1, 0, 1])
1.00303599234
>>> zscore(2, [21, 22, 19, 18, 17, 22, 20, 20, 1, 2, 3, 1, 2, 1, 0, 1])
-0.922793112954
>>> zscore(9, [1, 2, 0, 3, 1, 3, 1, 2, 9, 8, 7, 10, 9, 5, 2, 4, 1, 1, 0])
1.65291949506

Appunti

  • È possibile utilizzare questo metodo con una finestra scorrevole (ovvero gli ultimi 30 giorni) se si desidera non tenere conto di molta cronologia, il che renderà le tendenze a breve termine più pronunciate e ridurrà i tempi di elaborazione.

  • È inoltre possibile utilizzare un punteggio z per valori come la modifica delle viste da un giorno al giorno successivo per individuare i valori anomali per aumentare / ridurre le viste al giorno. È come usare la pendenza o la derivata del grafico delle viste al giorno.

  • Se si tiene traccia delle dimensioni correnti della popolazione, del totale attuale della popolazione e del totale attuale di x ^ 2 della popolazione, non è necessario ricalcolare questi valori, aggiornarli e quindi è sufficiente mantenere questi valori per la cronologia, non per ciascun valore di dati. Il seguente codice lo dimostra.

    from math import sqrt
    
    class zscore:
        def __init__(self, pop = []):
            self.number = float(len(pop))
            self.total = sum(pop)
            self.sqrTotal = sum(x ** 2 for x in pop)
        def update(self, value):
            self.number += 1.0
            self.total += value
            self.sqrTotal += value ** 2
        def avg(self):
            return self.total / self.number
        def std(self):
            return sqrt((self.sqrTotal / self.number) - self.avg() ** 2)
        def score(self, obs):
            return (obs - self.avg()) / self.std()
    
  • Utilizzando questo metodo il flusso di lavoro sarebbe il seguente. Per ogni argomento, tag o pagina creare un campo a virgola mobile, per il numero totale di giorni, la somma delle visualizzazioni e la somma delle visualizzazioni quadrate nel database. Se si dispone di dati storici, inizializzare questi campi utilizzando tali dati, altrimenti inizializzare a zero. Alla fine di ogni giornata, calcola il punteggio z utilizzando il numero di visualizzazioni del giorno rispetto ai dati storici memorizzati nei tre campi del database. Gli argomenti, i tag o le pagine con i punteggi Z più alti sono le X "tendenze più calde" della giornata. Infine, aggiorna ciascuno dei 3 campi con il valore del giorno e ripeti il ​​processo domani.

Nuova aggiunta

I punteggi z normali come discusso sopra non tengono conto dell'ordine dei dati e quindi il punteggio z per un'osservazione di '1' o '9' avrebbe la stessa grandezza rispetto alla sequenza [1, 1, 1, 1 , 9, 9, 9, 9]. Ovviamente per la ricerca delle tendenze, i dati più recenti dovrebbero avere più peso rispetto ai dati più vecchi e quindi vogliamo che l'osservazione "1" abbia un punteggio di grandezza maggiore rispetto all'osservazione "9". Per raggiungere questo obiettivo, propongo un punteggio z mobile medio. Dovrebbe essere chiaro che questo metodo NON è garantito per essere statisticamente valido ma dovrebbe essere utile per trovare tendenze o simili. La differenza principale tra lo z-score standard e lo z-score medio mobile è l'uso di una media mobile per calcolare il valore medio della popolazione e il valore medio della popolazione al quadrato. Vedi il codice per i dettagli:

Codice

class fazscore:
    def __init__(self, decay, pop = []):
        self.sqrAvg = self.avg = 0
        # The rate at which the historic data's effect will diminish.
        self.decay = decay
        for x in pop: self.update(x)
    def update(self, value):
        # Set initial averages to the first value in the sequence.
        if self.avg == 0 and self.sqrAvg == 0:
            self.avg = float(value)
            self.sqrAvg = float((value ** 2))
        # Calculate the average of the rest of the values using a 
        # floating average.
        else:
            self.avg = self.avg * self.decay + value * (1 - self.decay)
            self.sqrAvg = self.sqrAvg * self.decay + (value ** 2) * (1 - self.decay)
        return self
    def std(self):
        # Somewhat ad-hoc standard deviation calculation.
        return sqrt(self.sqrAvg - self.avg ** 2)
    def score(self, obs):
        if self.std() == 0: return (obs - self.avg) * float("infinity")
        else: return (obs - self.avg) / self.std()

IO di esempio

>>> fazscore(0.8, [1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9]).score(1)
-1.67770595327
>>> fazscore(0.8, [1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9]).score(9)
0.596052006642
>>> fazscore(0.9, [2, 4, 4, 4, 5, 5, 7, 9]).score(12)
3.46442230724
>>> fazscore(0.9, [2, 4, 4, 4, 5, 5, 7, 9]).score(22)
7.7773245459
>>> fazscore(0.9, [21, 22, 19, 18, 17, 22, 20, 20]).score(20)
-0.24633160155
>>> fazscore(0.9, [21, 22, 19, 18, 17, 22, 20, 20, 1, 2, 3, 1, 2, 1, 0, 1]).score(20)
1.1069362749
>>> fazscore(0.9, [21, 22, 19, 18, 17, 22, 20, 20, 1, 2, 3, 1, 2, 1, 0, 1]).score(2)
-0.786764452966
>>> fazscore(0.9, [1, 2, 0, 3, 1, 3, 1, 2, 9, 8, 7, 10, 9, 5, 2, 4, 1, 1, 0]).score(9)
1.82262469243
>>> fazscore(0.8, [40] * 200).score(1)
-inf

Aggiornare

Come correttamente sottolineato da David Kemp, se viene richiesta una serie di valori costanti e quindi viene richiesto un punteggio z per un valore osservato che differisce dagli altri valori, il risultato dovrebbe probabilmente essere diverso da zero. In effetti il ​​valore restituito dovrebbe essere infinito. Quindi ho cambiato questa linea,

if self.std() == 0: return 0

per:

if self.std() == 0: return (obs - self.avg) * float("infinity")

Questa modifica si riflette nel codice della soluzione fazscore. Se non si desidera gestire valori infiniti, una soluzione accettabile potrebbe essere invece quella di modificare la riga in:

if self.std() == 0: return obs - self.avg

1
No, il tuo codice ha un piccolo errore, nella riga seguente. $ z_score = $ hits_today - ($ average_hits_per_day / $ standard_deviation); Dovrebbe essere: $ z_score = ($ hits_today- $ average_hits_per_day) / $ standard_deviation; Nota il cambiamento tra parentesi.
Nixuz,

1
@nixuz - mi sto perdendo qualcosa: fazscore (0.8, map (lambda x: 40, range (0,200))). score (1) == 0 (per qualsiasi valore)?
kͩeͣmͮpͥ ͩ

1
@Nixus - Ho pensato di scavare questo dalla tomba. Potresti postare di nuovo l'implementazione di PHP? I pastecollegamenti non sembrano funzionare ... grazie!
Drewness,

1
Per chiunque lo desideri, ora ho query SQL per farlo.
thouliha,

1
Il decadimento qui è contro intuitivo; se si immettono 2 valori, ad esempio [10, 20] con un decadimento di 0,8, AVG è 10 * 0,8 + 20 * 0,2 = 12. Ti aspetteresti un valore superiore a 15, poiché 20 dovrebbe avere un peso maggiore di 10 in caso di decadimento. C'è un'alternativa molto migliore disponibile usando una media ponderata in numpy.average, in cui si crea un elenco parallelo con pesi. Ad esempio: data = range (10,30,10) decadimento = 0,8 decay_weights = [decadimento ** a per a in range (len (data), 0, -1)] print np.average (data, pesi = decay_weights)
Jeroen,

93

Hai bisogno di un algoritmo che misura la velocità di un argomento - o in altre parole, se lo grafici, vuoi mostrare quelli che stanno salendo a un ritmo incredibile.

Questa è la prima derivata della linea di tendenza e non è difficile incorporarla come fattore ponderato del calcolo complessivo.

Normalizzare

Una tecnica che devi fare è normalizzare tutti i tuoi dati. Per ogni argomento che stai seguendo, mantieni un filtro passa-basso che definisce la baseline di quell'argomento. Ora tutti i punti di dati relativi a quell'argomento dovrebbero essere normalizzati: sottrai la sua linea di base e otterrai TUTTI i tuoi argomenti vicino a 0, con punte sopra e sotto la linea. Potresti invece voler dividere il segnale per la sua grandezza di base, che porterà il segnale a circa 1,0 - questo non solo porta tutti i segnali in linea tra loro (normalizza la linea di base), ma normalizza anche i picchi. Un picco di britney sarà di magnitudo più grande di quello di qualcun altro, ma ciò non significa che dovresti prestare attenzione ad esso - il picco potrebbe essere molto piccolo rispetto alla sua linea di base.

Derivare

Dopo aver normalizzato tutto, capire la pendenza di ciascun argomento. Prendi due punti consecutivi e misura la differenza. Una differenza positiva è in aumento, una differenza negativa è in calo. Quindi puoi confrontare le differenze normalizzate e scoprire quali argomenti stanno aumentando in popolarità rispetto ad altri argomenti - con ogni argomento ridimensionato appropriato al proprio "normale" che può essere di ordine di grandezza diverso dagli altri argomenti.

Questo è davvero un primo passo al problema. Esistono tecniche più avanzate che dovrai utilizzare (principalmente una combinazione di quanto sopra con altri algoritmi, ponderate per soddisfare le tue esigenze) ma dovrebbe essere sufficiente per iniziare.

Per quanto riguarda l'articolo

L'articolo tratta della tendenza dell'argomento, ma non riguarda il modo in cui calcolare ciò che è caldo e ciò che non lo è, si tratta di come elaborare l'enorme quantità di informazioni che un tale algoritmo deve elaborare in luoghi come Lycos e Google. Lo spazio e il tempo necessari per assegnare a ciascun argomento un contatore e trovare il contatore di ogni argomento quando viene eseguita una ricerca su di esso è enorme. Questo articolo riguarda le sfide che si affrontano quando si tenta un simile compito. Parla dell'effetto Brittney, ma non parla di come superarlo.

Come sottolineato da Nixuz, questo viene anche definito Z o punteggio standard .


1
L'ho votato prima della modifica e torno indietro e volevo votarlo di nuovo! Bel lavoro
mmcdole,

Grazie! Vorrei fare lo pseudo codice, ma non ho il tempo in questo momento. Forse più tardi, o forse qualcun altro prenderà questi concetti e li implementerà ...
Adam Davis,

Grazie mille, Adam Davis! Se Nixuz ha davvero descritto la stessa cosa, penso di avere una soluzione in PHP: paste.bradleygill.com/index.php?paste_id=9206 Pensi che questo codice sia giusto?
Caw

Non dovrebbe essere l'accelerazione dell'argomento piuttosto che la velocità? Scopri l'ultima risposta
Sap,

17

Chad Birch e Adam Davis hanno ragione nel dire che dovrai guardare indietro per stabilire una linea di base. La tua domanda, come formulata, suggerisce che desideri visualizzare solo i dati delle ultime 24 ore e che non voleranno del tutto.

Un modo per dare un po 'di memoria ai tuoi dati senza dover cercare una grande quantità di dati storici è usare una media mobile esponenziale. Il vantaggio è che puoi aggiornarlo una volta per periodo e quindi scaricare tutti i vecchi dati, quindi devi solo ricordare un singolo valore. Quindi, se il tuo ciclo è un giorno, devi mantenere un attributo "media giornaliera" per ogni argomento, che puoi fare:

a_n = a_(n-1)*b + c_n*(1-b)

Dov'è a_nla media mobile del giorno n, b è una costante tra 0 e 1 (più vicino a 1, più lunga è la memoria) ed c_nè il numero di hit nel giorno n. Il bello è che se esegui questo aggiornamento alla fine della giornata n, puoi scaricare c_ne a_(n-1).

L'unica avvertenza è che sarà inizialmente sensibile a qualsiasi cosa tu scelga per il tuo valore iniziale di a.

MODIFICARE

Se aiuta a visualizzare questo approccio, prendere n = 5, a_0 = 1e b = .9.

Diciamo che i nuovi valori sono 5,0,0,1,4:

a_0 = 1
c_1 = 5 : a_1 = .9*1 + .1*5 = 1.4
c_2 = 0 : a_2 = .9*1.4 + .1*0 = 1.26
c_3 = 0 : a_3 = .9*1.26 + .1*0 = 1.134
c_4 = 1 : a_4 = .9*1.134 + .1*1 = 1.1206
c_5 = 4 : a_5 = .9*1.1206 + .1*5 = 1.40854

Non assomiglia molto a una media? Nota come il valore è rimasto vicino a 1, anche se il nostro input successivo era 5. Cosa sta succedendo? Se espandi la matematica, ottieni quello:

a_n = (1-b)*c_n + (1-b)*b*c_(n-1) + (1-b)*b^2*c_(n-2) + ... + (leftover weight)*a_0

Cosa intendo per peso residuo? Bene, in media, tutti i pesi devono aggiungere a 1. Se n fosse infinito e il ... potrebbe andare avanti all'infinito, allora tutti i pesi si sommerebbero a 1. Ma se n è relativamente piccolo, si ottiene una buona quantità di peso rimanente sull'input originale.

Se studi la formula sopra, dovresti capire alcune cose su questo utilizzo:

  1. Tutti i dati contribuisce qualcosa alla media per sempre. In pratica, c'è un punto in cui il contributo è davvero, davvero piccolo.
  2. I valori recenti contribuiscono più dei valori precedenti.
  3. Più b è alto, più nuovi sono i valori meno importanti e i valori più vecchi contano. Tuttavia, maggiore è la b, maggiore è il numero di dati necessari per annacquare il valore iniziale di a.

Penso che le prime due caratteristiche siano esattamente ciò che stai cercando. Per darti un'idea di ciò semplice da implementare, ecco un'implementazione di Python (meno tutte le interazioni con il database):

>>> class EMA(object):
...  def __init__(self, base, decay):
...   self.val = base
...   self.decay = decay
...   print self.val
...  def update(self, value):
...   self.val = self.val*self.decay + (1-self.decay)*value
...   print self.val
... 
>>> a = EMA(1, .9)
1
>>> a.update(10)
1.9
>>> a.update(10)
2.71
>>> a.update(10)
3.439
>>> a.update(10)
4.0951
>>> a.update(10)
4.68559
>>> a.update(10)
5.217031
>>> a.update(10)
5.6953279
>>> a.update(10)
6.12579511
>>> a.update(10)
6.513215599
>>> a.update(10)
6.8618940391
>>> a.update(10)
7.17570463519

1
Questo è anche noto come filtro di risposta all'impulso infinito (IIR)
Adam Davis,

Ehi, una versione migliore della mia risposta.
Giosuè,

@Adam Davvero? Non li conosco. È un caso speciale di un IIR? Gli articoli che sto scremando non sembrano fornire formule che si riducano a una media mobile esponenziale nel caso semplice.
David Berger,

Grazie mille, David Berger! Se funziona, sarebbe un'ottima aggiunta alle altre risposte! Ho alcune domande, però. Spero che tu possa rispondere a loro: 1) Il fattore b definisce la velocità con cui i vecchi dati stanno perdendo peso? 2) Questo approccio fornirà risultati approssimativamente equivalenti rispetto alla semplice memorizzazione dei vecchi dati e al calcolo della media? 3) È questa la tua formula in parole? $ average_value = $ old_average_value * $ smoothing_factor + $ hits_today * (1- $ smoothing_factor)
caw

I punti 1 e 3 sono corretti. Vedi la mia modifica per un po 'di una discussione sfumata di 2.
David Berger,

8

Tipicamente "buzz" viene capito usando una qualche forma di meccanismo di decadimento esponenziale / log. Per una panoramica di come Hacker News, Reddit e altri gestiscono questo in modo semplice, vedi questo post .

Questo non affronta completamente le cose che sono sempre popolari. Quello che stai cercando sembra essere qualcosa come la funzione " Hot Trends " di Google . Per questo, potresti dividere il valore corrente per un valore storico e quindi sottrarre quelli che sono al di sotto di una soglia di rumore.


Sì, Hot Trends di Google è esattamente quello che sto cercando. Quale dovrebbe essere il valore storico? Il valore medio degli ultimi 7 giorni, ad esempio?
Caw

1
Dipende da quanto sono volatili i tuoi dati. Potresti iniziare con una media di 30 giorni. Se è una cosa ciclica (ad esempio Kentucky Derby), potrebbe avere senso fare confronti annuali. Sperimenterei e vedrei cosa funziona meglio in pratica.
Jeff Moser,

7

Penso che la parola chiave che devi notare sia "anormalmente". Per determinare quando qualcosa è "anormale", devi sapere cosa è normale. Cioè, avrai bisogno di dati storici, che puoi calcolare in media per scoprire la normale frequenza di una particolare query. È possibile che si desideri escludere giorni anomali dal calcolo della media, ma ciò richiederà nuovamente di disporre di dati sufficienti, in modo da sapere in quali giorni escludere.

Da lì, dovrai impostare una soglia (che richiederebbe sperimentazione, ne sono certo), e se qualcosa va oltre la soglia, diciamo il 50% in più di ricerche del normale, puoi considerarla una "tendenza". Oppure, se vuoi essere in grado di trovare la "Top X più alla moda" come hai menzionato, devi solo ordinare le cose in base a quanto (in percentuale) sono lontane dal loro tasso normale.

Ad esempio, supponiamo che i tuoi dati storici ti abbiano detto che Britney Spears di solito riceve 100.000 ricerche e Paris Hilton di solito ne ottiene 50.000. Se hai un giorno in cui entrambi ricevono 10.000 ricerche in più del normale, dovresti considerare Parigi "più calda" di Britney, perché le sue ricerche sono aumentate del 20% in più del normale, mentre quelle di Britney erano solo del 10%.

Dio, non riesco a credere di aver appena scritto un paragrafo che confronta "hotness" di Britney Spears e Paris Hilton. Cosa mi hai fatto?


Grazie, ma sarebbe un po 'troppo facile ordinarli solo per il loro aumento progressivo, no?
Caw

7

Mi chiedevo se fosse possibile usare la normale formula di accelerazione fisica in tal caso?

v2-v1/t or dv/dt

Possiamo considerare v1 come like / voti / conteggio dei commenti iniziali all'ora e v2 come "velocità" attuale all'ora nelle ultime 24 ore?

È più una domanda che una risposta, ma sembra che funzioni. Qualsiasi contenuto con la massima accelerazione sarà l'argomento di tendenza ...

Sono sicuro che questo potrebbe non risolvere il problema di Britney Spears :-)


Funzionerà, in quanto calcola solo l'aumento di voto / like per volta, e questo è ciò di cui abbiamo bisogno. Potrebbe risolvere il "problema delle lance Britney" in parte perché questo termine di ricerca ha sempre un valore elevato v1e avrebbe bisogno di un livello molto alto v2per essere considerato "di tendenza". Tuttavia, ci sono probabilmente formule e algoritmi migliori e più sofisticati per farlo. Tuttavia, è un esempio funzionante di base.
Caw

In un contesto in cui devi sempre avere qualcosa nel feed "di tendenza", questo è perfetto. Qualcosa come una scheda Esplora in cui elenchi ciò che è il migliore sulla piattaforma in questo momento. Usando un altro algoritmo, potresti finire con un set di risultati vuoto.
Kilianc,

5

probabilmente un semplice gradiente di frequenza degli argomenti funzionerebbe - grande gradiente positivo = crescente rapidamente in popolarità.

il modo più semplice sarebbe quello di archiviare il numero di ricerche ogni giorno, in modo da avere qualcosa di simile

searches = [ 10, 7, 14, 8, 9, 12, 55, 104, 100 ]

e poi scopri quanto è cambiato di giorno in giorno:

hot_factor = [ b-a for a, b in zip(searches[:-1], searches[1:]) ]
# hot_factor is [ -3, 7, -6, 1, 3, 43, 49, -4 ]

e basta applicare una sorta di soglia in modo che i giorni in cui l'aumento è stato> 50 siano considerati "caldi". potresti renderlo molto più complicato, se lo desideri. piuttosto che la differenza assoluta puoi prendere la differenza relativa in modo che passare da 100 a 150 sia considerato caldo, ma da 1000 a 1050 no. o un gradiente più complicato che tiene conto delle tendenze per più di un giorno all'altro.


Grazie. Ma non so esattamente cos'è un gradiente e come posso lavorarci. Scusa!
Caw,

Grazie. Quindi devo costruire un vettore contenente la frequenza giornaliera, giusto? I valori relativi sarebbero migliori, ne sono sicuro. Esempio: una crescita da 100 a 110 non è buona come una crescita da 1 a 9, direi. Ma non c'è una funzione vettoriale che posso usare per trovare gli argomenti più interessanti? Valutare solo i valori relativi non sarebbe sufficiente, vero? Una crescita da 100 a 200 (100%) non è buona come una crescita da 20.000 a 39.000 !?
Caw,

A quale tipo di sito web stai aggiungendo questo? Il suggerimento di @Autoplectic di contare il cambiamento nelle ricerche giorno per giorno non si ridimensionerà bene per qualcosa come un forum popolare, in cui hai migliaia di argomenti con nuovi definiti ogni giorno.
Quantum7,

Hai ragione, ho bisogno di un algoritmo per enormi quantità di dati, migliaia di argomenti all'ora.
Caw

questa è una strategia scadente. in questo modo, un aumento totale di 50 ricerche su Britney Spears è caldo come +50 ricerche su un nuovo referendum in Europa.
Iman Akbari,

4

Avevo lavorato a un progetto, in cui il mio obiettivo era trovare argomenti di tendenza dal Live Twitter Stream e fare anche analisi sentimentali sugli argomenti di tendenza (scoprire se l'argomento di tendenza parlava positivamente / negativamente). Ho usato Storm per gestire il flusso di Twitter.

Ho pubblicato il mio rapporto come blog: http://sayrohan.blogspot.com/2013/06/finding-trending-topics-and-trending.html

Ho usato il conteggio totale e il punteggio Z per la classifica.

L'approccio che ho usato è un po 'generico, e nella sezione di discussione, ho menzionato come estendere il sistema per un'applicazione non Twitter.

Spero che l'informazione aiuti.


3

Se guardi semplicemente tweet o messaggi di stato per ottenere i tuoi argomenti, sentirai molto rumore. Anche se rimuovi tutte le parole di stop. Un modo per ottenere un sottoinsieme migliore di candidati all'argomento è concentrarsi solo su tweet / messaggi che condividono un URL e ottenere le parole chiave dal titolo di tali pagine Web. E assicurati di applicare la codifica POS per ottenere anche nomi + frasi di nomi.

I titoli delle pagine Web di solito sono più descrittivi e contengono parole che descrivono di cosa tratta la pagina. Inoltre, la condivisione di una pagina Web di solito è correlata alla condivisione di notizie che stanno rompendo (cioè se una celebrità come Michael Jackson è morta, avrai molte persone che condividono un articolo sulla sua morte).

Ho condotto esperimenti in cui prendo solo parole chiave popolari dai titoli, quindi ottengo il conteggio totale di tali parole chiave in tutti i messaggi di stato e rimuovono sicuramente molto rumore. Se lo fai in questo modo, non hai bisogno di un algoritmo complesso, fai semplicemente un ordinamento delle frequenze delle parole chiave e sei a metà strada.


2

È possibile utilizzare i rapporti log-verosimiglianza per confrontare la data corrente con l'ultimo mese o anno. Questo è statisticamente valido (dato che i tuoi eventi non sono normalmente distribuiti, il che deve essere assunto dalla tua domanda).

Basta ordinare tutti i termini per logLR e scegliere i primi dieci.

public static void main(String... args) {
    TermBag today = ...
    TermBag lastYear = ...
    for (String each: today.allTerms()) {
        System.out.println(logLikelihoodRatio(today, lastYear, each) + "\t" + each);
    }
} 

public static double logLikelihoodRatio(TermBag t1, TermBag t2, String term) {
    double k1 = t1.occurrences(term); 
    double k2 = t2.occurrences(term); 
    double n1 = t1.size(); 
    double n2 = t2.size(); 
    double p1 = k1 / n1;
    double p2 = k2 / n2;
    double p = (k1 + k2) / (n1 + n2);
    double logLR = 2*(logL(p1,k1,n1) + logL(p2,k2,n2) - logL(p,k1,n1) - logL(p,k2,n2));
    if (p1 < p2) logLR *= -1;
    return logLR;
}

private static double logL(double p, double k, double n) {
    return (k == 0 ? 0 : k * Math.log(p)) + ((n - k) == 0 ? 0 : (n - k) * Math.log(1 - p));
}

PS, un TermBag è una raccolta non ordinata di parole. Per ogni documento crei un sacco di termini. Basta contare le occorrenze delle parole. Quindi il metodo occurrencesrestituisce il numero di occorrenze di una determinata parola e il metodo sizerestituisce il numero totale di parole. È meglio normalizzare le parole in qualche modo, in genere toLowerCaseè abbastanza buono. Ovviamente, negli esempi precedenti creeresti un documento con tutte le query di oggi e uno con tutte le query dell'ultimo anno.


Spiacenti, non capisco il codice. Cosa sono i termbag? Sarebbe bello se potessi spiegare a breve cosa fa questo codice.
Caw

1
Un TermBag è un insieme di termini, ovvero la classe dovrebbe essere in grado di rispondere al numero totale di parole nel testo e al numero di occorrenze per ogni parola.
Akuhn,

0

L'idea è quella di tenere traccia di tali cose e notare quando saltano in modo significativo rispetto alla propria linea di base.

Quindi, per le query che hanno più di una certa soglia, tenere traccia di ognuna e quando cambia in un valore (diciamo quasi il doppio) del suo valore storico, allora è una nuova tendenza calda.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.