web-dev-qa-db-fra.com

Comment obtenir une distribution lognormale en Python avec Mu et Sigma?

J'ai essayé d'obtenir le résultat d'une distribution lognormal en utilisant Scipy . J'ai déjà le Mu et Sigma, donc je n'ai pas besoin de faire d'autres travaux préparatoires. Si j'ai besoin d'être plus précis (et j'essaie d'être avec ma connaissance limitée des statistiques), je dirais que je cherche la fonction cumulative (cdf sous Scipy). Le problème est que je ne peux pas comprendre comment faire cela avec juste la moyenne et l'écart type sur une échelle de 0-1 (c'est-à-dire que la réponse renvoyée devrait être quelque chose de 0-1). Je ne sais pas non plus quelle méthode de dist, je devrais utiliser pour obtenir la réponse. J'ai essayé de lire la documentation et de parcourir SO, mais les questions pertinentes (comme ceci et ceci ) ne semblaient pas fournir les réponses que je cherchais.

Voici un exemple de code de ce avec quoi je travaille. Merci.

from scipy.stats import lognorm
stddev = 0.859455801705594
mean = 0.418749176686875
total = 37
dist = lognorm.cdf(total,mean,stddev)

METTRE À JOUR:

Donc, après un peu de travail et quelques recherches, je suis allé un peu plus loin. Mais je reçois toujours la mauvaise réponse. Le nouveau code est ci-dessous. Selon R et Excel, le résultat devrait être .7434, mais ce n'est clairement pas ce qui se passe. Y a-t-il une faille logique qui me manque?

dist = lognorm([1.744],loc=2.0785)
dist.cdf(25)  # yields=0.96374596, expected=0.7434

UPDATE 2: Implémentation de lognorm de travail donnant le résultat correct 0.7434.

def lognorm(self,x,mu=0,sigma=1):
   a = (math.log(x) - mu)/math.sqrt(2*sigma**2)
   p = 0.5 + 0.5*math.erf(a)
   return p
lognorm(25,1.744,2.0785)
> 0.7434
20
Eric Lubow

Il semble que vous souhaitiez instancier une distribution "gelée" à partir de paramètres connus. Dans votre exemple, vous pourriez faire quelque chose comme:

from scipy.stats import lognorm
stddev = 0.859455801705594
mean = 0.418749176686875
dist=lognorm([stddev],loc=mean)

qui vous donnera un objet de distribution lognorm avec la moyenne et l’écart-type que vous spécifiez. Vous pouvez alors obtenir le pdf ou le cdf comme ceci:

import numpy as np
import pylab as pl
x=np.linspace(0,6,200)
pl.plot(x,dist.pdf(x))
pl.plot(x,dist.cdf(x))

lognorm cdf and pdf

Est-ce ce que vous aviez en tête?

14
talonmies

Je sais que c'est un peu tard (presque un an!), Mais je suis en train de faire des recherches sur la fonction lognorm dans scipy.stats. Beaucoup de gens semblent confus au sujet des paramètres d'entrée, alors j'espère pouvoir les aider. L'exemple ci-dessus est presque correct, mais j'ai trouvé étrange de définir la moyenne sur le paramètre location ("loc"). Cela indique que la cdf ou le pdf ne "décolle" pas tant que la valeur n'est pas supérieure à la moyenne. De plus, les arguments moyen et écart type doivent être sous la forme exp (Ln (moyenne)) et Ln (StdDev), respectivement.

En termes simples, les arguments sont (x, forme, loc, échelle), avec les définitions de paramètre ci-dessous:

loc - Pas d'équivalent, cela est soustrait de vos données pour que 0 devienne l'infimum de la plage de données.

scale - exp μ, où μ est la moyenne du log de la variable. (Lors de l'ajustement, vous utiliserez généralement la moyenne d'échantillon du journal des données.)

forme - l'écart type du journal de la variable.

J'ai vécu la même frustration que la plupart des gens avec cette fonction, alors je partage ma solution. Soyez prudent, car les explications ne sont pas très claires sans un compendium de ressources.

Pour plus d'informations, j'ai trouvé ces sources utiles:

Et voici un exemple, tiré de la réponse de @serv-inc, postée sur cette page ici:

import math
from scipy import stats

# standard deviation of normal distribution
sigma = 0.859455801705594
# mean of normal distribution
mu = 0.418749176686875
# hopefully, total is the value where you need the cdf
total = 37

frozen_lognorm = stats.lognorm(s=sigma, scale=math.exp(mu))
frozen_lognorm.cdf(total) # use whatever function and value you need here
29
modulitos
from math import exp
from scipy import stats

def lognorm_cdf(x, mu, sigma):
    shape  = sigma
    loc    = 0
    scale  = exp(mu)
    return stats.lognorm.cdf(x, shape, loc, scale)

x      = 25
mu     = 2.0785
sigma  = 1.744
p      = lognorm_cdf(x, mu, sigma)  #yields the expected 0.74341

Semblable à Excel et à R, la fonction lognorm_cdf ci-dessus paramètre le CDF pour la distribution log-normale à l'aide de mu et sigma.

Bien que SciPy utilise forme, loc et échelle paramètres pour caractériser ses distributions de probabilité, pour la distribution log-normale, je trouve légèrement plus facile de penser à ces paramètres à le niveau variable plutôt qu'au niveau de la distribution. Voici ce que je veux dire ...

Une variable log-normale X est liée à une variable normale Z comme suit:

X = exp(mu + sigma * Z)              #Equation 1

qui est le même que:

X = exp(mu) * exp(Z)**sigma          #Equation 2

Cela peut être ré-écrit sournoisement comme suit:

X = exp(mu) * exp(Z-Z0)**sigma       #Equation 3

Z0 = 0. Cette équation est de la forme:

f(x) = a * ( (x-x0) ** b )           #Equation 4

Si vous pouvez visualiser des équations dans votre tête, il est clair que les paramètres d'échelle, de forme et d'emplacement de l'équation 4 sont: a, b et x0, respectivement. . Cela signifie que dans l'équation 3, les paramètres d'échelle, de forme et d'emplacement sont les suivants: exp (mu)}, sigma et zéro, respectueusement.

Si vous ne pouvez pas visualiser cela très clairement, réécrivons l'équation 2 comme une fonction:

f(Z) = exp(mu) * exp(Z)**sigma      #(same as Equation 2)

et ensuite regarder les effets de mu et sigma sur f(Z). La figure ci-dessous tient sigma constante et varie mu. Vous devriez voir que mu est verticalement mis à l'échelle f(Z). Cependant, il le fait de manière non linéaire; l'effet de changer mu de 0 à 1 est plus petit que l'effet de changer mu de 1 à 2. De l'équation 2, nous voyons que exp (mu) est en fait le facteur d'échelle linéaire. Par conséquent, "l'échelle" de SciPy est exp (mu)}.

 effects_of_mu

La figure suivante contient mu constante et varie sigma. Vous devriez voir que la forme de f(Z) change. C’est-à-dire que f(Z) a une valeur constante lorsque Z = 0 et sigma affecte la rapidité avec f(Z) s'éloigne de l'axe horizontal. La "forme" de SciPy est donc sigma.

 effects_of_sigma

9
ToddP

Encore plus tard, mais au cas où cela serait utile à quelqu'un d'autre: j'ai trouvé que les Excel

LOGNORM.DIST(x,Ln(mean),standard_dev,TRUE)

fournit les mêmes résultats que python

from scipy.stats import lognorm
lognorm.cdf(x,sigma,0,mean)

De même, Excel

LOGNORM.DIST(x,Ln(mean),standard_dev,FALSE)

semble équivalent à Python

from scipy.stats import lognorm
lognorm.pdf(x,sigma,0,mean).
3
Docuemada

La réponse de @lucas a l'usage bas. Comme exemple de code, vous pouvez utiliser

import math
from scipy import stats

# standard deviation of normal distribution
sigma = 0.859455801705594
# mean of normal distribution
mu = 0.418749176686875
# hopefully, total is the value where you need the cdf
total = 37

frozen_lognorm = stats.lognorm(s=sigma, scale=math.exp(mu))
frozen_lognorm.cdf(total) # use whatever function and value you need here
2
serv-inc

Si vous lisez ceci et que vous voulez juste une fonction ayant un comportement similaire à lnorm dans R. Bien, alors libérez-vous de la colère violente et utilisez le numpy.random.lognormal de numpy.

0
Kristian Davidsen