J'essaie de recréer un ajustement de distribution de probabilité maximale, je peux déjà le faire dans Matlab et R, mais maintenant je veux utiliser scipy. En particulier, je voudrais estimer les paramètres de distribution de Weibull pour mon ensemble de données.
J'ai essayé ceci:
import scipy.stats as s
import numpy as np
import matplotlib.pyplot as plt
def weib(x,n,a):
return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a)
data = np.loadtxt("stack_data.csv")
(loc, scale) = s.exponweib.fit_loc_scale(data, 1, 1)
print loc, scale
x = np.linspace(data.min(), data.max(), 1000)
plt.plot(x, weib(x, loc, scale))
plt.hist(data, data.max(), normed=True)
plt.show()
Et obtenez ceci:
(2.5827280639441961, 3.4955032285727947)
Et une distribution qui ressemble à ceci:
J'utilise le exponweib
après avoir lu ceci http://www.johndcook.com/distributions_scipy.html . J'ai également essayé les autres fonctions de Weibull en scipy (juste au cas où!).
Dans Matlab (en utilisant l'outil Distribution Fitting - voir capture d'écran) et en R (en utilisant à la fois la fonction de bibliothèque MASS fitdistr
et le package GAMLSS) j'obtiens des paramètres a (loc) et b (échelle) plus comme 1.58463497 5.93030013. Je crois que les trois méthodes utilisent la méthode du maximum de vraisemblance pour l'ajustement de la distribution.
J'ai posté mes données ici si vous souhaitez vous lancer! Et pour être complet, j'utilise Python 2.7.5, Scipy 0.12.0, R 2.15.2 et Matlab 2012b.
Pourquoi est-ce que j'obtiens un résultat différent!?
Je suppose que vous voulez estimer le paramètre de forme et l'échelle de la distribution de Weibull tout en gardant l'emplacement fixe. Fixer loc
suppose que les valeurs de vos données et de la distribution sont positives avec une borne inférieure à zéro.
floc=0
maintient l'emplacement fixe à zéro, f0=1
maintient le premier paramètre de forme de la bulle exponentielle fixé à un.
>>> stats.exponweib.fit(data, floc=0, f0=1)
[1, 1.8553346917584836, 0, 6.8820748596850905]
>>> stats.weibull_min.fit(data, floc=0)
[1.8553346917584836, 0, 6.8820748596850549]
L'ajustement par rapport à l'histogramme semble correct, mais pas très bon. Les estimations des paramètres sont un peu plus élevées que celles que vous mentionnez proviennent de R et de matlab.
Mise à jour
Le plus proche que je peux obtenir de l'intrigue qui est maintenant disponible est avec un ajustement sans restriction, mais en utilisant des valeurs de départ. L'intrigue est encore moins culminée. Les valeurs de note en ajustement qui n'ont pas de f devant sont utilisées comme valeurs de départ.
>>> from scipy import stats
>>> import matplotlib.pyplot as plt
>>> plt.plot(data, stats.exponweib.pdf(data, *stats.exponweib.fit(data, 1, 1, scale=02, loc=0)))
>>> _ = plt.hist(data, bins=np.linspace(0, 16, 33), normed=True, alpha=0.5);
>>> plt.show()
Il est facile de vérifier quel résultat est le vrai MLE, il suffit d'avoir une fonction simple pour calculer la vraisemblance du journal:
>>> def wb2LL(p, x): #log-likelihood
return sum(log(stats.weibull_min.pdf(x, p[1], 0., p[0])))
>>> adata=loadtxt('/home/user/stack_data.csv')
>>> wb2LL(array([6.8820748596850905, 1.8553346917584836]), adata)
-8290.1227946678173
>>> wb2LL(array([5.93030013, 1.57463497]), adata)
-8410.3327470347667
Le résultat de la méthode fit
de exponweib
et R fitdistr
(@Warren) est meilleur et a une probabilité de log plus élevée. Il est plus probable que ce soit le vrai MLE. Il n'est pas surprenant que le résultat de GAMLSS soit différent. Il s'agit d'un modèle statistique complètement différent: le modèle additif généralisé.
Toujours pas convaincu? Nous pouvons dessiner un tracé de limite de confiance 2D autour de MLE, voir le livre de Meeker et Escobar pour plus de détails).
Encore une fois, cela vérifie que array([6.8820748596850905, 1.8553346917584836])
est la bonne réponse car loglik vraisemblance est inférieure à tout autre point dans l'espace des paramètres. Remarque:
>>> log(array([6.8820748596850905, 1.8553346917584836]))
array([ 1.92892018, 0.61806511])
BTW1, l'ajustement MLE ne semble pas correspondre étroitement à l'histogramme de distribution. Une manière simple de penser au MLE est que le MLE est l'estimation de paramètre la plus probable compte tenu des données observées. Il n'a pas besoin d'ajuster visuellement l'histogramme, ce qui minimisera l'erreur quadratique moyenne.
BTW2, vos données semblent être leptokurtiques et asymétriques à gauche, ce qui signifie que la distribution de Weibull peut ne pas convenir à vos données. Essayez, par exemple Gompertz-Logistic, qui améliore la probabilité de log d'environ 100 autres. À votre santé!
Je sais que c'est un ancien message, mais je viens de faire face à un problème similaire et ce fil m'a aidé à le résoudre. J'ai pensé que ma solution pourrait être utile pour d'autres comme moi:
# Fit Weibull function, some explanation below
params = stats.exponweib.fit(data, floc=0, f0=1)
shape = params[1]
scale = params[3]
print 'shape:',shape
print 'scale:',scale
#### Plotting
# Histogram first
values,bins,hist = plt.hist(data,bins=51,range=(0,25),normed=True)
center = (bins[:-1] + bins[1:]) / 2.
# Using all params and the stats function
plt.plot(center,stats.exponweib.pdf(center,*params),lw=4,label='scipy')
# Using my own Weibull function as a check
def weibull(u,shape,scale):
'''Weibull distribution for wind speed u with shape parameter k and scale parameter A'''
return (shape / scale) * (u / scale)**(shape-1) * np.exp(-(u/scale)**shape)
plt.plot(center,weibull(center,shape,scale),label='Wind analysis',lw=2)
plt.legend()
Quelques informations supplémentaires qui m'ont aidé à comprendre:
La fonction Scipy Weibull peut prendre quatre paramètres d'entrée: (a, c), loc et échelle. Vous voulez fixer le loc et le premier paramètre de forme (a), cela se fait avec floc = 0, f0 = 1. L'ajustement vous donnera alors les paramètres c et échelle, où c correspond au paramètre de forme de la distribution de Weibull à deux paramètres (souvent utilisé dans l'analyse des données de vent) et l'échelle correspond à son facteur d'échelle.
Depuis les documents:
exponweib.pdf(x, a, c) =
a * c * (1-exp(-x**c))**(a-1) * exp(-x**c)*x**(c-1)
Si a vaut 1, alors
exponweib.pdf(x, a, c) =
c * (1-exp(-x**c))**(0) * exp(-x**c)*x**(c-1)
= c * (1) * exp(-x**c)*x**(c-1)
= c * x **(c-1) * exp(-x**c)
À partir de là, la relation avec la fonction Weibull "d'analyse du vent" devrait être plus claire.
J'étais curieux de votre question et, bien que ce ne soit pas une réponse, il compare le résultat Matlab
avec votre résultat et avec le résultat utilisant leastsq
, qui a montré la meilleure corrélation avec les données données:
Le code est comme suit:
import scipy.stats as s
import numpy as np
import matplotlib.pyplot as plt
import numpy.random as mtrand
from scipy.integrate import quad
from scipy.optimize import leastsq
## my distribution (Inverse Normal with shape parameter mu=1.0)
def weib(x,n,a):
return (a / n) * (x / n)**(a-1) * np.exp(-(x/n)**a)
def residuals(p,x,y):
integral = quad( weib, 0, 16, args=(p[0],p[1]) )[0]
penalization = abs(1.-integral)*100000
return y - weib(x, p[0],p[1]) + penalization
#
data = np.loadtxt("stack_data.csv")
x = np.linspace(data.min(), data.max(), 100)
n, bins, patches = plt.hist(data,bins=x, normed=True)
binsm = (bins[1:]+bins[:-1])/2
popt, pcov = leastsq(func=residuals, x0=(1.,1.), args=(binsm,n))
loc, scale = 1.58463497, 5.93030013
plt.plot(binsm,n)
plt.plot(x, weib(x, loc, scale),
label='weib matlab, loc=%1.3f, scale=%1.3f' % (loc, scale), lw=4.)
loc, scale = s.exponweib.fit_loc_scale(data, 1, 1)
plt.plot(x, weib(x, loc, scale),
label='weib stack, loc=%1.3f, scale=%1.3f' % (loc, scale), lw=4.)
plt.plot(x, weib(x,*popt),
label='weib leastsq, loc=%1.3f, scale=%1.3f' % Tuple(popt), lw=4.)
plt.legend(loc='upper right')
plt.show()
Il y a déjà eu quelques réponses à cela ici et ailleurs. likt in distribution de Weibull et les données dans la même figure (avec numpy et scipy)
Il m'a encore fallu un certain temps pour trouver un exemple de jouet propre, donc j'ai pensé qu'il serait utile de poster.
from scipy import stats
import matplotlib.pyplot as plt
#input for pseudo data
N = 10000
Kappa_in = 1.8
Lambda_in = 10
a_in = 1
loc_in = 0
#Generate data from given input
data = stats.exponweib.rvs(a=a_in,c=Kappa_in, loc=loc_in, scale=Lambda_in, size = N)
#The a and loc are fixed in the fit since it is standard to assume they are known
a_out, Kappa_out, loc_out, Lambda_out = stats.exponweib.fit(data, f0=a_in,floc=loc_in)
#Plot
bins = range(51)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(bins, stats.exponweib.pdf(bins, a=a_out,c=Kappa_out,loc=loc_out,scale = Lambda_out))
ax.hist(data, bins = bins , normed=True, alpha=0.5)
ax.annotate("Shape: $k = %.2f$ \n Scale: $\lambda = %.2f$"%(Kappa_out,Lambda_out), xy=(0.7, 0.85), xycoords=ax.transAxes)
plt.show()
J'ai eu le même problème, mais j'ai constaté que le paramètre loc=0
dans exponweib.fit
a amorcé la pompe pour l'optimisation. C'était tout ce qu'il fallait de @ user333700 réponse . Je n'ai pas pu charger vos données - votre liaison de données pointe vers une image, pas des données. J'ai donc effectué un test sur mes données à la place:
import scipy.stats as ss
import matplotlib.pyplot as plt
import numpy as np
N=30
counts, bins = np.histogram(x, bins=N)
bin_width = bins[1]-bins[0]
total_count = float(sum(counts))
f, ax = plt.subplots(1, 1)
f.suptitle(query_uri)
ax.bar(bins[:-1]+bin_width/2., counts, align='center', width=.85*bin_width)
ax.grid('on')
def fit_pdf(x, name='lognorm', color='r'):
dist = getattr(ss, name) # params = shape, loc, scale
# dist = ss.gamma # 3 params
params = dist.fit(x, loc=0) # 1-day lag minimum for shipping
y = dist.pdf(bins, *params)*total_count*bin_width
sqerror_sum = np.log(sum(ci*(yi - ci)**2. for (ci, yi) in Zip(counts, y)))
ax.plot(bins, y, color, lw=3, alpha=0.6, label='%s err=%3.2f' % (name, sqerror_sum))
return y
colors = ['r-', 'g-', 'r:', 'g:']
for name, color in Zip(['exponweib', 't', 'gamma'], colors): # 'lognorm', 'erlang', 'chi2', 'weibull_min',
y = fit_pdf(x, name=name, color=color)
ax.legend(loc='best', frameon=False)
plt.show()
l'ordre du loc et de l'échelle est gâché dans le code:
plt.plot(x, weib(x, scale, loc))
le paramètre d'échelle doit venir en premier.