2012-01-05 12 views
22

Chcę dopasować dystrybucję lognormalną do moich danych, używając python scipy.stats.lognormal.fit. Zgodnie z manual, fit zwraca parametry , loc, scale. Jednak dystrybucja logormormalnie wymaga tylko two parameters: średniej i odchylenia standardowego.scipy, lognormal distribution - parametry

Jak interpretować wyniki funkcji scipy fit? Jak zdobyć średnią i std.dev.?

Odpowiedz

20

Rozkłady w scipy są kodowane w sposób ogólny WRT dwa lokalizacji parametrów i stopniu, tak że położenie to parametr (loc), który przesuwa się dystrybucję w lewo lub w prawo, podczas gdy scale jest parametrem, który ściska lub rozciąga rozkład .

Dla dwóch parametrów rozkładu logarytmicznego "średnia" i "std dev" odpowiadają logowi (scale) i shape (można pozwolić loc=0).

Poniżej przedstawiono, jak dopasować rozkład logarytmicznie normalny znaleźć dwa parametry zainteresowania:

In [56]: import numpy as np 

In [57]: from scipy import stats 

In [58]: logsample = stats.norm.rvs(loc=10, scale=3, size=1000) # logsample ~ N(mu=10, sigma=3) 

In [59]: sample = np.exp(logsample) # sample ~ lognormal(10, 3) 

In [60]: shape, loc, scale = stats.lognorm.fit(sample, floc=0) # hold location to 0 while fitting 

In [61]: shape, loc, scale 
Out[61]: (2.9212650122639419, 0, 21318.029350592606) 

In [62]: np.log(scale), shape # mu, sigma 
Out[62]: (9.9673084420467362, 2.9212650122639419) 
+4

dwa komentarze: nastąpił błąd w scipy 0,9 z kłaczków, która została ustalona w scipy 0,10 http://projects.scipy.org/scipy/ticket/1536 a po drugie dlatego, generycznego parametryzacji dystrybucja lognormalna nie ma zwykłej parametryzacji, na przykład http://projects.scipy.org/scipy/ticket/1502. – user333700

+0

dzięki za poprawki. Nie dostałem drugiego - z komentarzy w linku wydaje się, że nie ma tam żadnego błędu ...? –

+0

@JakubM. Tak, jeśli używasz najnowszego scipy (0.10), powyższa odpowiedź/przykład nie jest sprzeczna z żadnym z biletów wymienionych w komentarzu użytkownika user33700. – ars

5

po prostu spędzić trochę czasu pracy na to uwagę i chciał ją udokumentować tutaj: Jeśli chcesz uzyskać prawdopodobieństwo gęstość (w punkcie x) z trzech wartości powrotnymi lognorm.fit (nazwijmy je (shape, loc, scale)), trzeba korzystać z tego wzoru:

x = 1/(shape*((x-loc)/scale)*sqrt(2*pi)) * exp(-1/2*(log((x-loc)/scale)/shape)**2)/scale 

tak jak równanie, które jest (loc jest µ, shape jest σ i scale jest α):

x = \frac{1}{(x-\mu)\cdot\sqrt{2\pi\sigma^2}} \cdot e^{-\frac{log(\frac{x-\mu}{\alpha})^2}{2\sigma^2}}

+0

Dlaczego dzielimy przez (1/alfa) na końcu twojej formuły? – bioslime

+1

To nie jest moja formuła, ale sposób, w jaki działa scipy. Nie widzę żadnego podziału przez (1/α} na końcu, więc zakładam, że mówisz o podziale przez 'scale' - popraw mnie, jeśli źle zrozumiałem.) Spojrzałem na ten kod jakiś czas temu, ale jeśli pamiętajcie o tym poprawnie, tak jest w przypadku każdego rodzaju dystrybucji, ale zauważcie, że na początku jest jeszcze inna "skala", a oni się wzajemnie znoszą (jak widać w równaniu): – Chronial

-1

Myślę, że to pomoże. Szukałem tego samego problemu przez długi czas iw końcu znalazłem rozwiązanie dla mojego problemu. W moim przypadku, Próbowałem dopasować niektóre dane do dystrybucji lognormalnej przy użyciu modułu scipy.stats.lognorm. Jednakże, gdy w końcu dostałem parametry modelu, nie mogłem znaleźć sposobu na powtórzenie wyników przy użyciu wartości średniej i std z y.

W poniższym kodzie wyjaśniam na podstawie parametrów średnich i standardowych, jak utworzyć próbkę danych o rozkładzie normalnym za pomocą modułu scipy.stats.norm. Korzystając z tych danych, dopasowuję normalny model (norm_dist_fitted), a także tworzę normalny model, używając wyodrębnionego z danych średniej i standardowego odchylenia (mu, sigma).

Oryginalny model produkujący dane, dopasowany i wyprodukowany po (mu-sigma) -parę jest porównywany na wykresie.

Fig1


W następnej części kodu używać normalnych danych w celu wytworzenia próbki logarytmiczno-normalny rozdzielone. Aby to zrobić, należy zauważyć, że próbki logormalne będą wykładnicze dla oryginalnej próbki. Zatem średnie i standardowe odchylenie próbki wykładniczej będzie wynosić (exp(mu) i exp(sigma)).

I wyposażone wytworzonych danych do lognormal (od dziennik mojego próbki (exp (x)) jest normalnie rozprowadzane i wykonaj lognormal założeń modelowych.

celu wytworzenia logarytmiczno-normalny model z średniej i odchylenia standardowego z oryginalnych danych (x) kod będzie:

lognorm_dist = scipy.stats.lognorm(s=sigma, loc=0, scale=np.exp(mu)) 

Jednakże, jeśli dane są już w wykładniczej przestrzeni (exp (x)), następnie trzeba użyć:

muX = np.mean(np.log(x)) 
sigmaX = np.std(np.log(x)) 
scipy.stats.lognorm(s=sigmaX, loc=0, scale=muX) 

Fig2

import scipy 
import matplotlib.pyplot as plt 
import seaborn as sns 
import numpy as np 

mu = 10 # Mean of sample !!! Make sure your data is positive for the lognormal example 
sigma = 1.5 # Standard deviation of sample 
N = 2000 # Number of samples 

norm_dist = scipy.stats.norm(loc=mu, scale=sigma) # Create Random Process 
x = norm_dist.rvs(size=N) # Generate samples 

# Fit normal 
fitting_params = scipy.stats.norm.fit(x) 
norm_dist_fitted = scipy.stats.norm(*fitting_params) 
t = np.linspace(np.min(x), np.max(x), 100) 

# Plot normals 
f, ax = plt.subplots(1, sharex='col', figsize=(10, 5)) 
sns.distplot(x, ax=ax, norm_hist=True, kde=False, label='Data X~N(mu={0:.1f}, sigma={1:.1f})'.format(mu, sigma)) 
ax.plot(t, norm_dist_fitted.pdf(t), lw=2, color='r', 
     label='Fitted Model X~N(mu={0:.1f}, sigma={1:.1f})'.format(norm_dist_fitted.mean(), norm_dist_fitted.std())) 
ax.plot(t, norm_dist.pdf(t), lw=2, color='g', ls=':', 
     label='Original Model X~N(mu={0:.1f}, sigma={1:.1f})'.format(norm_dist.mean(), norm_dist.std())) 
ax.legend(loc='lower right') 
plt.show() 


# The lognormal model fits to a variable whose log is normal 
# We create our variable whose log is normal 'exponenciating' the previous variable 

x_exp = np.exp(x) 
mu_exp = np.exp(mu) 
sigma_exp = np.exp(sigma) 

fitting_params_lognormal = scipy.stats.lognorm.fit(x_exp, floc=0, scale=mu_exp) 
lognorm_dist_fitted = scipy.stats.lognorm(*fitting_params_lognormal) 
t = np.linspace(np.min(x_exp), np.max(x_exp), 100) 

# Here is the magic I was looking for a long long time 
lognorm_dist = scipy.stats.lognorm(s=sigma, loc=0, scale=np.exp(mu)) 

# The trick is to understand these two things: 
# 1. If the EXP of a variable is NORMAL with MU and STD -> EXP(X) ~ scipy.stats.lognorm(s=sigma, loc=0, scale=np.exp(mu)) 
# 2. If your variable (x) HAS THE FORM of a LOGNORMAL, the model will be scipy.stats.lognorm(s=sigmaX, loc=0, scale=muX) 
# with: 
# - muX = np.mean(np.log(x)) 
# - sigmaX = np.std(np.log(x)) 


# Plot lognormals 
f, ax = plt.subplots(1, sharex='col', figsize=(10, 5)) 
sns.distplot(x_exp, ax=ax, norm_hist=True, kde=False, 
      label='Data exp(X)~N(mu={0:.1f}, sigma={1:.1f})\n X~LogNorm(mu={0:.1f}, sigma={1:.1f})'.format(mu, sigma)) 
ax.plot(t, lognorm_dist_fitted.pdf(t), lw=2, color='r', 
     label='Fitted Model X~LogNorm(mu={0:.1f}, sigma={1:.1f})'.format(lognorm_dist_fitted.mean(), lognorm_dist_fitted.std())) 
ax.plot(t, lognorm_dist.pdf(t), lw=2, color='g', ls=':', 
     label='Original Model X~LogNorm(mu={0:.1f}, sigma={1:.1f})'.format(lognorm_dist.mean(), lognorm_dist.std())) 
ax.legend(loc='lower right') 
plt.show() 
+0

Proszę podać trochę wyjaśnienie towarzyszące twojej odpowiedzi: –

+0

@ CollinM.Barrett Zrobione!: DI nadzieję, że jest ok: D –