Quel est l'algorithme correct pour une courbe de distribution logarthmique entre deux points ?

StackOverflow https://stackoverflow.com/questions/604953

  •  03-07-2019
  •  | 
  •  

Question

J'ai lu de nombreux tutoriels sur la manière appropriée de générer une distribution logarithmique des poids des nuages ​​de balises.La plupart d’entre eux regroupent les balises en étapes.Cela me semble un peu idiot, j'ai donc développé mon propre algorithme basé sur ce que j'ai lu afin qu'il répartisse dynamiquement le nombre de tags le long de la courbe logarthmique entre le seuil et le maximum.En voici l'essence en 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

Fondamentalement, sans le calcul logarithmique du nombre individuel, cela générerait une ligne droite entre les points (mincount, minsize) et (maxcount, maxsize).

L’algorithme fait une bonne approximation de la courbe entre les deux points, mais souffre d’un inconvénient.Le mincount est un cas particulier, et son logarithme produit zéro.Cela signifie que la taille du mincount serait inférieure à minsize.J'ai essayé de concocter des chiffres pour tenter de résoudre ce cas particulier, mais je n'arrive pas à y parvenir.Actuellement, je traite simplement le mincount comme un cas particulier et j'ajoute "or 1" à la ligne logcount.

Existe-t-il un algorithme plus correct pour tracer une courbe entre les deux points ?

Mise à jour du 3 mars:Si je ne me trompe pas, je prends le journal du décompte et je le branche ensuite dans une équation linéaire.Pour mettre la description du cas particulier en d’autres termes, en y=lnx à x=1, y=0.C'est ce qui se passe au décompte minutieux.Mais le mincount ne peut pas être nul, le tag n'a pas été utilisé 0 fois.

Essayez le code et branchez vos propres numéros pour tester.Traiter le mincount comme un cas particulier me convient, j'ai le sentiment que ce serait plus facile que quelle que soit la solution réelle à ce problème.J'ai juste l'impression d'être là doit être une solution à ce problème et que quelqu'un a probablement trouvé une solution.

MISE À JOUR 6 avril:Un simple Google la recherche révèle de nombreux tutoriels que j'ai lus, mais ce est probablement l'exemple le plus complet de nuages ​​de tags étagés.

MISE À JOUR 28 avril:En réponse à la solution d'antti.huima :Lorsqu'elle est représentée graphiquement, la courbe créée par votre algorithme se situe sous la ligne entre les deux points.J'ai essayé de jongler avec les chiffres, mais je n'arrive toujours pas à trouver un moyen d'inverser cette courbe de l'autre côté de la ligne.Je suppose que si la fonction était modifiée en une forme de logarithme au lieu d'un exposant, elle ferait exactement ce dont j'aurais besoin.Est-ce exact?Si oui, quelqu'un peut-il expliquer comment y parvenir ?

Était-ce utile?

La solution

Grâce à l'aide d'antti.huima, j'ai repensé ce que j'essayais de faire.

En prenant sa méthode de résolution du problème, je veux une équation où le logarithme du compte minimum est égal à l'équation linéaire entre les deux points.

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

Bien que cela me donne un bon point de départ, je dois le faire passer par le point (MAX, max_weight).Il va falloir une constante :

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

En résolvant K, nous obtenons :

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

Donc, pour remettre tout cela dans du code 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

Autres conseils

Commençons par votre mappage du nombre enregistré à la taille.C'est le mappage linéaire que vous avez mentionné :

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

où min et max sont les min et max tailles, et a=log(maxcount)-b.La ligne est de y=mx+c où x=log(count)-b

À partir du graphique, nous pouvons voir que le gradient, m, est (maxsize-minsize)/a.

Nous avons besoin de x=0 à y=minsize, donc log(mincount)-b=0 -> b=log(mincount)

Cela nous laisse avec le python suivant :

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

Si vous voulez vous assurer que le nombre minimum est toujours au moins 1, remplacez la première ligne par :

mincount = min(count+[1])

qui ajoute 1 à la liste de comptage avant de faire le min.Il en va de même pour s'assurer que le nombre maximum est toujours au moins 1.Ainsi, votre code final ci-dessus est :

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

ce que vous avez, c'est que vous avez des balises dont le nombre va de MIN à MAX ;la question du seuil peut être ignorée ici car elle revient à définir chaque décompte inférieur au seuil à la valeur seuil et à prendre le minimum et le maximum seulement ensuite.

Vous souhaitez mapper le nombre de balises sur des « poids » mais de manière « logarithmique », ce qui signifie essentiellement (si je comprends bien) ce qui suit.Tout d'abord, les balises avec le nombre MAX obtiennent le poids max_weight (dans votre exemple, 1,75) :

weight(MAX) = max_weight

Deuxièmement, les balises avec le nombre MIN obtiennent le poids min_weight (dans votre exemple, 0,75) :

weight(MIN) = min_weight

Enfin, lorsque votre compte diminue de 1, le poids est multiplié par une constante K < 1, ce qui indique la pente de la courbe :

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

En résolvant cela, nous obtenons :

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

Notez que avec x = MAX, l'exposant est nul et le multiplicande de droite devient 1.

Nous avons maintenant l’exigence supplémentaire queweight(MIN) = min_weight, et nous pouvons résoudre :

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

d'où nous obtenons

K ^ (MAX - MIN) = weight_min / weight_max

et en prenant le logarithme des deux côtés

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

c'est à dire.

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

Le côté droit est négatif comme souhaité, car K < 1.Alors

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

Alors maintenant, vous avez la formule pour calculer K.Après cela, il vous suffit de demander n'importe quel nombre x entre MIN et MAX :

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

Et vous avez terminé.

Sur une échelle logarithmique, vous tracez simplement le journal des nombres de manière linéaire (en d'autres termes, faites semblant de tracer linéairement, mais prenez d'abord le journal des nombres à tracer).

Le problème du zéro ne peut pas être résolu analytiquement : vous devez choisir un ordre de grandeur minimum pour votre échelle, et quoi qu'il en soit, vous ne pourrez jamais atteindre zéro.Si vous souhaitez tracer quelque chose à zéro, vous avez le choix de lui donner arbitrairement l'ordre de grandeur minimum de l'échelle, ou de l'omettre.

Je n'ai pas la réponse exacte, mais je pense que vous souhaitez rechercher linéarisation des données exponentielles.Commencez par calculer l’équation de la droite passant par les points et prenez le log des deux côtés de cette équation.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top