Domanda

Ho letto una serie di tutorial sul modo corretto di generare una distribuzione logaritmica dei pesi tagcloud. La maggior parte di essi raggruppa i tag in passaggi. Questo mi sembra in qualche modo sciocco, quindi ho sviluppato il mio algoritmo basato su ciò che ho letto in modo che distribuisca dinamicamente il conteggio del tag lungo la curva logarthmic tra la soglia e il massimo. Ecco l'essenza di esso in Python:

from math import log
count = [1, 3, 5, 4, 7, 5, 10, 6]
def logdist(count, threshold=0, maxsize=1.75, minsize=.75):
    countdist = []
    # mincount is either the threshold or the minimum if it's over the threshold
    mincount = threshold<min(count) and min(count) or threshold
    maxcount = max(count)
    spread = maxcount - mincount
    # the slope of the line (rise over run) between (mincount, minsize) and ( maxcount, maxsize)
    delta = (maxsize - minsize) / float(spread)
    for c in count:
        logcount = log(c - (mincount - 1)) * (spread + 1) / log(spread + 1)
        size = delta * logcount - (delta - minsize)
        countdist.append({'count': c, 'size': round(size, 3)})
    return countdist

Fondamentalmente, senza il calcolo logaritmico del conteggio individuale, genererebbe una linea retta tra i punti (mincount, minsize) e (maxcount, maxsize).

L'algoritmo esegue una buona approssimazione della curva tra i due punti, ma presenta un inconveniente. Il mincount è un caso speciale e il logaritmo di esso produce zero. Ciò significa che la dimensione del conteggio minimo sarebbe inferiore alla dimensione minima. Ho provato a cucinare i numeri per cercare di risolvere questo caso speciale, ma non riesco a farlo bene. Attualmente considero il mincount come un caso speciale e aggiungo & Quot; or 1 & Quot; alla riga del logcount.

Esiste un algoritmo più corretto per disegnare una curva tra i due punti?

Aggiorna il 3 marzo : se non sbaglio, prendo il registro del conteggio e lo inserisco in un'equazione lineare. Per mettere la descrizione del caso speciale in altre parole, in y = lnx in x = 1, y = 0. Questo è ciò che accade al mincount. Ma il numero minimo non può essere zero, il tag non è stato usato 0 volte.

Prova il codice e collega i tuoi numeri per testare. Trattare il mincount come un caso speciale va bene per me, ho la sensazione che sarebbe più facile di qualunque sia la soluzione effettiva a questo problema. Sento che deve essere una soluzione a questo e che qualcuno probabilmente ha trovato una soluzione.

AGGIORNAMENTO 6 aprile : un semplice google la ricerca mostra molti dei tutorial che ho letto, ma questo è probabilmente l'esempio più completo di nuvole di tag a gradini.

AGGIORNAMENTO 28 aprile : in risposta alla soluzione di antti.huima: se rappresentata graficamente, la curva creata dall'algoritmo si trova sotto la linea tra i due punti. Ho cercato di destreggiarmi tra i numeri ma non riesco ancora a trovare un modo per invertire quella curva dall'altra parte della linea. Immagino che se la funzione fosse cambiata in una qualche forma di logaritmo anziché in un esponente farebbe esattamente ciò di cui avrei bisogno. È corretto? In tal caso, qualcuno può spiegare come raggiungere questo obiettivo?

È stato utile?

Soluzione

Grazie all'aiuto di antti.huima, ho ripensato a ciò che stavo cercando di fare.

Prendendo il suo metodo per risolvere il problema, voglio un'equazione in cui il logaritmo del mincount sia uguale all'equazione lineare tra i due punti.

weight(MIN) = ln(MIN-(MIN-1)) + min_weight
min_weight = ln(1) + min_weight

Mentre questo mi dà un buon punto di partenza, devo farlo passare attraverso il punto (MAX, max_weight). Avrà bisogno di una costante:

weight(x) = ln(x-(MIN-1))/K + min_weight

Risolvendo per K otteniamo:

K = ln(MAX-(MIN-1))/(max_weight - min_weight)

Quindi, per rimetterlo tutto in un po 'di codice Python:

from math import log
count = [1, 3, 5, 4, 7, 5, 10, 6]
def logdist(count, threshold=0, maxsize=1.75, minsize=.75):
    countdist = []
    # mincount is either the threshold or the minimum if it's over the threshold
    mincount = threshold<min(count) and min(count) or threshold
    maxcount = max(count)
    constant = log(maxcount - (mincount - 1)) / (maxsize - minsize)
    for c in count:
        size = log(c - (mincount - 1)) / constant + minsize
        countdist.append({'count': c, 'size': round(size, 3)})
    return countdist

Altri suggerimenti

Cominciamo con la mappatura dal conteggio registrato alla dimensione. Questa è la mappatura lineare che hai citato:

   size
    |
max |_____
    |   /
    |  /|
    | / |
min |/  |
    |   |
   /|   |
0 /_|___|____
    0   a

dove min e max sono le dimensioni min e max e a = log (maxcount) -b. La linea è di y = mx + c dove x = log (count) -b

Dal grafico, possiamo vedere che il gradiente, m, è (maxsize-minsize) / a.

Abbiamo bisogno di x = 0 in y = minsize, quindi log (mincount) -b = 0 - > b = log (MINCOUNT)

Questo ci lascia con il seguente pitone:

mincount = min(count)
maxcount = max(count)
xoffset = log(mincount)
gradient = (maxsize-minsize)/(log(maxcount)-log(mincount))
for c in count:
    x = log(c)-xoffset
    size = gradient * x + minsize

Se vuoi assicurarti che il conteggio minimo sia sempre almeno 1, sostituisci la prima riga con:

mincount = min(count+[1])

che aggiunge 1 all'elenco dei conteggi prima di eseguire il min. Lo stesso vale per assicurarsi che il maxcount sia sempre almeno 1. Quindi il tuo codice finale per sopra è:

from math import log
count = [1, 3, 5, 4, 7, 5, 10, 6]
def logdist(count, maxsize=1.75, minsize=.75):
    countdist = []
    mincount = min(count+[1])
    maxcount = max(count+[1])
    xoffset = log(mincount)
    gradient = (maxsize-minsize)/(log(maxcount)-log(mincount))
    for c in count:
        x = log(c)-xoffset
        size = gradient * x + minsize
        countdist.append({'count': c, 'size': round(size, 3)})
    return countdist

quello che hai è che hai tag i cui conteggi vanno da MIN a MAX; il problema della soglia può essere ignorato qui perché equivale a impostare ogni valore al di sotto della soglia sul valore di soglia e prendere il minimo e il massimo solo successivamente.

Si desidera mappare il conteggio dei tag su " pesi " ma in " modo logaritmico " ;, che in sostanza significa (come ho capito) il seguente. Innanzitutto, i tag con conteggio MAX ottengono peso max_weight (nel tuo esempio 1,75):

weight(MAX) = max_weight

In secondo luogo, i tag con il conteggio MIN ottengono peso min_weight (nel tuo esempio, 0,75):

weight(MIN) = min_weight

Infine, sostiene che quando il conteggio diminuisce di 1, il peso viene moltiplicato per una costante K < 1, che indica la pendenza della curva:

weight(x) = weight(x + 1) * K

Risolvendo questo, otteniamo:

weight(x) = weight_max * (K ^ (MAX - x))

Nota che con x = MAX, l'esponente è zero e il multiplicando a destra diventa 1.

Ora abbiamo il requisito aggiuntivo che weight (MIN) = min_weight, e possiamo risolvere:

weight_min = weight_max * (K ^ (MAX - MIN))

da cui otteniamo

K ^ (MAX - MIN) = weight_min / weight_max

e prendendo il logaritmo su entrambi i lati

(MAX - MIN) ln K = ln weight_min - ln weight_max

cioè.

ln K = (ln weight_min - ln weight_max) / (MAX - MIN)

Il lato destro è negativo come desiderato, perché K < 1. Quindi

K = exp((ln weight_min - ln weight_max) / (MAX - MIN))

Quindi ora hai la formula per calcolare K. Dopo questo ti basterà fare domanda per qualsiasi conteggio tra MIN e MAX:

weight(x) = max_weight * (K ^ (MAX - x))

E il gioco è fatto.

Su una scala di registro, traccia semplicemente il registro dei numeri in modo lineare (in altre parole, fai finta che stai tramando in modo lineare, ma prendi prima il registro dei numeri da tracciare).

Il problema zero non può essere risolto analiticamente: devi scegliere un ordine di grandezza minimo per la tua bilancia, e qualunque cosa tu non possa mai raggiungere zero. Se vuoi tracciare qualcosa a zero, le tue scelte sono di dargli arbitrariamente il minimo ordine di grandezza della scala, o di ometterlo.

Non ho la risposta esatta, ma penso che tu voglia cercare Linearizzare i dati esponenziali. Inizia calcolando l'equazione della linea che passa attraverso i punti e prendi il registro di entrambi i lati dell'equazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top