5 Stimmen

Was ist der richtige Algorithmus für eine logarithmische Verteilungskurve zwischen zwei Punkten?

Ich habe eine Reihe von Tutorials über die richtige Methode zur Erzeugung einer logarithmischen Verteilung von Gewichten für Tagclouds gelesen. Die meisten von ihnen gruppieren die Tags in Schritte. Das erscheint mir etwas albern, deshalb habe ich meinen eigenen Algorithmus entwickelt, basierend auf dem, was ich gelesen habe, so dass er dynamisch die Anzahl der Tags entlang der logarithmischen Kurve zwischen dem Grenzwert und dem Maximum verteilt. Hier ist das Wesentliche davon 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 ist entweder der Grenzwert oder das Minimum, wenn es über dem Grenzwert liegt
    mincount = threshold

``

Grundsätzlich würde es ohne die logarithmische Berechnung des individuellen Zählwerts eine Gerade zwischen den Punkten, (mincount, minsize) und (maxcount, maxsize) erzeugen.

Der Algorithmus liefert eine gute Näherung der Kurve zwischen den beiden Punkten, leidet jedoch an einem Nachteil. Der mincount ist ein Sonderfall, und der Logarithmus davon ergibt null. Das bedeutet, dass die Größe des mincount kleiner als minsize wäre. Ich habe versucht, Zahlen zusammenzustellen, um diesen Sonderfall zu lösen, aber kann es nicht richtig hinbekommen. Derzeit behandle ich den mincount nur als Sonderfall und füge "or 1" zur logcount-Zeile hinzu.

Gibt es einen korrekteren Algorithmus, um eine Kurve zwischen den beiden Punkten zu zeichnen?

Update am 3. März: Wenn ich mich nicht irre, nehme ich den Logarithmus des Zählwerts und setze ihn dann in eine lineare Gleichung ein. Um die Beschreibung des Sonderfalls anders auszudrücken, bei y=lnx bei x=1, y=0. Das passiert beim mincount. Aber der mincount kann nicht null sein, das Tag wurde noch nicht 0 Mal verwendet.

Probieren Sie den Code aus und geben Sie Ihre eigenen Zahlen ein, um es zu testen. Den mincount als Sonderfall zu behandeln, ist für mich in Ordnung, ich habe das Gefühl, dass es einfacher wäre als die eigentliche Lösung für dieses Problem. Ich habe einfach das Gefühl, dass es eine Lösung dafür geben muss und dass vielleicht schon jemand eine Lösung gefunden hat.

UPDATE am 6. April: Eine einfache google-Suche zeigt viele der Tutorials, die ich gelesen habe, aber dies hier ist wahrscheinlich das vollständigste Beispiel für gestufte Tag-Clouds.

UPDATE am 28. April: Als Antwort auf die Lösung von antti.huima: Wenn man es grafisch darstellt, liegt die Kurve, die dein Algorithmus erzeugt, unter der Linie zwischen den beiden Punkten. Ich habe versucht, mit den Zahlen herumzuspielen, komme aber immer noch nicht darauf, wie ich diese Kurve auf die andere Seite der Linie bringen kann. Ich vermute, dass, wenn die Funktion in irgendeiner Form von Logarithmus statt einem Exponenten geändert wird, genau das passieren würde, was ich brauche. Ist das korrekt? Wenn ja, kann mir jemand erklären, wie man das erreichen kann?

``

2voto

dburke Punkte 1186

Dank antti.huima's Hilfe habe ich darüber nachgedacht, was ich versuchen wollte.

Indem ich seine Methode zur Lösung des Problems anwende, möchte ich eine Gleichung haben, bei der der Logarithmus der Mindestanzahl gleich der linearen Gleichung zwischen den beiden Punkten ist.

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

Obwohl mir dies einen guten Ausgangspunkt gibt, muss ich sicherstellen, dass es durch den Punkt (MAX, max_weight) verläuft. Es wird eine Konstante benötigen:

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

Beim Lösen für K erhalten wir:

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

Also, um dies alles wieder in etwas Python-Code zu setzen:

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 ist entweder der Schwellenwert oder das Minimum, wenn es über dem Schwellenwert liegt
    mincount = threshold

1voto

Phil H Punkte 19126

Beginnen wir mit Ihrer Zuordnung von der Protokollanzahl zur Größe. Das ist die lineare Zuordnung, von der Sie gesprochen haben:

   Größe
    |
max |\_\_\_\_\_
    |   /
    |  /|
    | / |
min |/  |
    |   |
   /|   |
0 /\_|\_\_\_|\_\_\_\_
    0   a

wo min und max die min und max Größen sind, und a=log(maxanzahl)-b. Die Linie ist von der Form y=mx+c, wobei x=log(anazhl)-b

Von dem Graphen können wir sehen, dass der Gradient, m, gleich (maxgröße-mingröße)/a ist.

Wir benötigen x=0 bei y=mingröße, also log(minanzahl)-b=0 -> b=log(minanzahl)

Dies hinterlässt uns mit dem folgenden Python-Code:

minanzahl = min(anzahl)
maxanzahl = max(anzahl)
xoffset = log(minanzahl)
gradient = (maxgröße-mingröße)/(log(maxanzahl)-log(minanzahl))
for c in anzahl:
    x = log(c)-xoffset
    größe = gradient * x + mingröße

Wenn Sie sicherstellen möchten, dass die Mindestanzahl immer mindestens 1 beträgt, ersetzen Sie die erste Zeile durch:

minanzahl = min(anzahl+[1])

was 1 an die Anzahl-Liste anhängt, bevor das Minimum ermittelt wird. Dasselbe gilt dafür, sicherzustellen, dass die Maximalanzahl immer mindestens 1 beträgt. Somit ist Ihr endgültiger Code gemäß dem obigen:

from math import log
anzahl = [1, 3, 5, 4, 7, 5, 10, 6]
def logdist(anzahl, maxgröße=1.75, mingröße=.75):
    anzahldist = []
    minanzahl = min(anzahl+[1])
    maxanzahl = max(anzahl+[1])
    xoffset = log(minanzahl)
    gradient = (maxgröße-mingröße)/(log(maxanzahl)-log(minanzahl))
    for c in anzahl:
        x = log(c)-xoffset
        größe = gradient * x + mingröße
        anzahldist.append({'anzahl': c, 'größe': round(größe, 3)})
    return anzahldist

1voto

Antti Huima Punkte 24441

Was Sie haben, sind Tags, deren Anzahl von MIN bis MAX reicht; das Schwellenwertproblem kann hier ignoriert werden, da es darauf hinausläuft, dass jede Anzahl unterhalb des Schwellenwerts auf den Schwellenwertwert gesetzt wird und erst danach das Minimum und Maximum genommen wird.

Sie möchten die Tag-Anzahlen "gewichten", aber auf "logarithmische Weise", was im Grunde genommen bedeutet (so wie ich es verstehe), folgendes. Erstens erhalten die Tags mit der Anzahl MAX ein Gewicht von max_weight (in Ihrem Beispiel 1,75):

weight(MAX) = max_weight

Zweitens erhalten die Tags mit der Anzahl MIN ein Gewicht von min_weight (in Ihrem Beispiel 0,75):

weight(MIN) = min_weight

Schließlich gilt, dass wenn Ihre Anzahl um 1 abnimmt, das Gewicht mit einer Konstante K < 1 multipliziert wird, die die Steilheit der Kurve angibt:

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

Wenn wir das lösen, erhalten wir:

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

Beachten Sie, dass bei x = MAX der Exponent null ist und der Multiplikator auf der rechten Seite zu 1 wird.

Jetzt haben wir die zusätzliche Anforderung, dass weight(MIN) = min_weight gilt, und wir können lösen:

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

woraus wir erhalten

K ^ (MAX - MIN) = weight_min / weight_max

und wenn wir auf beiden Seiten den Logarithmus nehmen

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

d.h.

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

Die rechte Seite ist wie gewünscht negativ, da K < 1. Dann gilt

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

Jetzt haben Sie also die Formel, um K zu berechnen. Danach wenden Sie einfach für jede Anzahl x zwischen MIN und MAX an:

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

Und Sie sind fertig.

0voto

Drew Hall Punkte 27579

Auf einer logarithmischen Skala plotst du einfach das Logarithmus der Zahlen linear (mit anderen Worten, stell dir vor, du plotst linear, nimm aber zuerst den Logarithmus der zu plotenden Zahlen).

Das Nullproblem kann nicht analytisch gelöst werden - du musst eine minimale Größenordnung für deine Skala festlegen, und egal was du tust, du kannst niemals null erreichen. Wenn du etwas bei null plotten möchtest, sind deine Möglichkeiten entweder, ihm willkürlich die minimale Größenordnung der Skala zu geben oder es auszulassen.

0voto

John Ellinwood Punkte 13961

Ich habe nicht die genaue Antwort, aber ich denke, du willst nach der Linearisierung exponentieller Daten suchen. Beginne damit, die Gleichung der Linie zu berechnen, die durch die Punkte verläuft, und nimm den Logarithmus beider Seiten dieser Gleichung.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X