J'utilise le code suivant pour s'adapter à la distribution normale. Le lien pour l'ensemble de données pour "b" (trop grand pour être publié directement) est:
setwd("xxxxxx")
library(fitdistrplus)
require(MASS)
tazur <-read.csv("b", header= TRUE, sep=",")
claims<-tazur$b
a<-log(claims)
plot(hist(a))
Après avoir tracé l'histogramme, il semble qu'une distribution normale devrait bien s'ajuster.
f1n <- fitdistr(claims,"normal")
summary(f1n)
#Length Class Mode
#estimate 2 -none- numeric
#sd 2 -none- numeric
#vcov 4 -none- numeric
#n 1 -none- numeric
#loglik 1 -none- numeric
plot(f1n)
Erreur dans xy.coords (x, y, xlabel, ylabel, log):
'x' est une liste, mais n'a pas les composants 'x' et 'y'
J'obtiens l'erreur ci-dessus lorsque j'essaie de tracer la distribution ajustée, et même les statistiques récapitulatives sont désactivées pour f1n.
J'apprécierais toute aide.
On dirait que vous faites de la confusion entre MASS::fitdistr
et fitdistrplus::fitdist
.
MASS::fitdistr
renvoie un objet de la classe "fitdistr", et il n'y a pas de méthode de tracé pour cela. Vous devez donc extraire les paramètres estimés et tracer vous-même la courbe de densité estimée.fitdistrplus
, car votre appel de fonction montre clairement que vous utilisez MASS
. Quoi qu'il en soit, fitdistrplus
a la fonction fitdist
qui renvoie l'objet de la classe "fitdist". Il existe une méthode de tracé pour cette classe, mais elle ne fonctionnera pas pour "fitdistr" renvoyé par MASS
.Je vais vous montrer comment travailler avec les deux packages.
## reproducible example
set.seed(0); x <- rnorm(500)
Utilisation de MASS::fitdistr
Aucune méthode de tracé n'est disponible, alors faites-le nous-mêmes.
library(MASS)
fit <- fitdistr(x, "normal")
class(fit)
# [1] "fitdistr"
para <- fit$estimate
# mean sd
#-0.0002000485 0.9886248515
hist(x, prob = TRUE)
curve(dnorm(x, para[1], para[2]), col = 2, add = TRUE)
Utilisation de fitdistrplus::fitdist
library(fitdistrplus)
FIT <- fitdist(x, "norm") ## note: it is "norm" not "normal"
class(FIT)
# [1] "fitdist"
plot(FIT) ## use method `plot.fitdist`
Examen de la réponse précédente
Dans la réponse précédente, je n'ai pas mentionné la différence entre deux méthodes. En général, si nous optons pour l'inférence du maximum de vraisemblance, je recommanderais d'utiliser MASS::fitdistr
, car pour de nombreuses distributions de base, il effectue une inférence exacte au lieu d'une optimisation numérique. Doc de ?fitdistr
l'a expliqué assez clairement:
For the Normal, log-Normal, geometric, exponential and Poisson
distributions the closed-form MLEs (and exact standard errors) are
used, and ‘start’ should not be supplied.
For all other distributions, direct optimization of the
log-likelihood is performed using ‘optim’. The estimated standard
errors are taken from the observed information matrix, calculated
by a numerical approximation. For one-dimensional problems the
Nelder-Mead method is used and for multi-dimensional problems the
BFGS method, unless arguments named ‘lower’ or ‘upper’ are
supplied (when ‘L-BFGS-B’ is used) or ‘method’ is supplied
explicitly.
D'autre part, fitdistrplus::fitdist
effectue toujours l'inférence de manière numérique, même s'il existe une inférence exacte. Bien sûr, l'avantage de fitdist
est que plus de principe d'inférence est disponible:
Fit of univariate distributions to non-censored data by maximum
likelihood (mle), moment matching (mme), quantile matching (qme)
or maximizing goodness-of-fit estimation (mge).
Objet de cette réponse
Cette réponse va explorer l'inférence exacte pour une distribution normale. Il aura une saveur théorique, mais il n'y a pas de principe de preuve de vraisemblance; seuls les résultats sont donnés. Sur la base de ces résultats, nous écrivons notre propre fonction R pour l'inférence exacte, qui peut être comparée à MASS::fitdistr
. En revanche, pour comparer avec fitdistrplus::fitdist
, nous utilisons optim
pour minimiser numériquement la fonction de log-vraisemblance négative.
C'est une excellente occasion d'apprendre des statistiques et une utilisation relativement avancée de optim
. Pour plus de commodité, je vais estimer le paramètre d'échelle: la variance, plutôt que l'erreur standard.
Inférence exacte de la distribution normale
Écriture de la fonction d'inférence nous-mêmes
Le code suivant est bien commenté. Il y a un interrupteur exact
. Si défini FALSE
, la solution numérique est choisie.
## fitting a normal distribution
fitnormal <- function (x, exact = TRUE) {
if (exact) {
################################################
## Exact inference based on likelihood theory ##
################################################
## minimum negative log-likelihood (maximum log-likelihood) estimator of `mu` and `phi = sigma ^ 2`
n <- length(x)
mu <- sum(x) / n
phi <- crossprod(x - mu)[1L] / n # (a bised estimator, though)
## inverse of Fisher information matrix evaluated at MLE
invI <- matrix(c(phi, 0, 0, phi * phi), 2L,
dimnames = list(c("mu", "sigma2"), c("mu", "sigma2")))
## log-likelihood at MLE
loglik <- -(n / 2) * (log(2 * pi * phi) + 1)
## return
return(list(theta = c(mu = mu, sigma2 = phi), vcov = invI, loglik = loglik, n = n))
}
else {
##################################################################
## Numerical optimization by minimizing negative log-likelihood ##
##################################################################
## negative log-likelihood function
## define `theta = c(mu, phi)` in order to use `optim`
nllik <- function (theta, x) {
(length(x) / 2) * log(2 * pi * theta[2]) + crossprod(x - theta[1])[1] / (2 * theta[2])
}
## gradient function (remember to flip the sign when using partial derivative result of log-likelihood)
## define `theta = c(mu, phi)` in order to use `optim`
gradient <- function (theta, x) {
pl2pmu <- -sum(x - theta[1]) / theta[2]
pl2pphi <- -crossprod(x - theta[1])[1] / (2 * theta[2] ^ 2) + length(x) / (2 * theta[2])
c(pl2pmu, pl2pphi)
}
## ask `optim` to return Hessian matrix by `hessian = TRUE`
## use "..." part to pass `x` as additional / further argument to "fn" and "gn"
## note, we want `phi` as positive so box constraint is used, with "L-BFGS-B" method chosen
init <- c(sample(x, 1), sample(abs(x) + 0.1, 1)) ## arbitrary valid starting values
z <- optim(par = init, fn = nllik, gr = gradient, x = x, lower = c(-Inf, 0), method = "L-BFGS-B", hessian = TRUE)
## post processing ##
theta <- z$par
loglik <- -z$value ## flip the sign to get log-likelihood
n <- length(x)
## Fisher information matrix (don't flip the sign as this is the Hessian for negative log-likelihood)
I <- z$hessian / n ## remember to take average to get mean
invI <- solve(I, diag(2L)) ## numerical inverse
dimnames(invI) <- list(c("mu", "sigma2"), c("mu", "sigma2"))
## return
return(list(theta = theta, vcov = invI, loglik = loglik, n = n))
}
}
Nous utilisons toujours les données précédentes pour les tests:
set.seed(0); x <- rnorm(500)
## exact inference
fit <- fitnormal(x)
#$theta
# mu sigma2
#-0.0002000485 0.9773790969
#
#$vcov
# mu sigma2
#mu 0.9773791 0.0000000
#sigma2 0.0000000 0.9552699
#
#$loglik
#[1] -703.7491
#
#$n
#[1] 500
hist(x, prob = TRUE)
curve(dnorm(x, fit$theta[1], sqrt(fit$theta[2])), add = TRUE, col = 2)
La méthode numérique est également assez précise, sauf que la covariance de la variance n'a pas exactement 0 sur la diagonale:
fitnormal(x, FALSE)
#$theta
#[1] -0.0002235315 0.9773732277
#
#$vcov
# mu sigma2
#mu 9.773826e-01 5.359978e-06
#sigma2 5.359978e-06 1.910561e+00
#
#$loglik
#[1] -703.7491
#
#$n
#[1] 500