Come determinare quale distribuzione si adatta meglio ai miei dati?


133

Ho un set di dati e vorrei capire quale distribuzione si adatta meglio ai miei dati.

Ho usato la fitdistr()funzione per stimare i parametri necessari per descrivere la distribuzione presunta (cioè Weibull, Cauchy, Normal). Usando questi parametri posso condurre un test di Kolmogorov-Smirnov per stimare se i miei dati del campione provengono dalla stessa distribuzione della mia distribuzione presunta.

Se il valore p è> 0,05, posso presumere che i dati del campione siano tratti dalla stessa distribuzione. Ma il valore p non fornisce alcuna informazione sulla divinità dell'adattamento, non è vero?

Quindi, nel caso in cui il valore p dei miei dati campione sia> 0,05 per una distribuzione normale e una distribuzione weibull, come posso sapere quale distribuzione si adatta meglio ai miei dati?

Questo è fondamentalmente quello che ho fatto:

> mydata
 [1] 37.50 46.79 48.30 46.04 43.40 39.25 38.49 49.51 40.38 36.98 40.00
[12] 38.49 37.74 47.92 44.53 44.91 44.91 40.00 41.51 47.92 36.98 43.40
[23] 42.26 41.89 38.87 43.02 39.25 40.38 42.64 36.98 44.15 44.91 43.40
[34] 49.81 38.87 40.00 52.45 53.13 47.92 52.45 44.91 29.54 27.13 35.60
[45] 45.34 43.37 54.15 42.77 42.88 44.26 27.14 39.31 24.80 16.62 30.30
[56] 36.39 28.60 28.53 35.84 31.10 34.55 52.65 48.81 43.42 52.49 38.00
[67] 38.65 34.54 37.70 38.11 43.05 29.95 32.48 24.63 35.33 41.34

# estimate shape and scale to perform KS-test for weibull distribution
> fitdistr(mydata, "weibull")
     shape        scale   
   6.4632971   43.2474500 
 ( 0.5800149) ( 0.8073102)

# KS-test for weibull distribution
> ks.test(mydata, "pweibull", scale=43.2474500, shape=6.4632971)

        One-sample Kolmogorov-Smirnov test

data:  mydata
D = 0.0686, p-value = 0.8669
alternative hypothesis: two-sided

# KS-test for normal distribution
> ks.test(mydata, "pnorm", mean=mean(mydata), sd=sd(mydata))

        One-sample Kolmogorov-Smirnov test

data:  mydata
D = 0.0912, p-value = 0.5522
alternative hypothesis: two-sided

I valori p sono 0,8669 per la distribuzione di Weibull e 0,5522 per la distribuzione normale. Quindi posso presumere che i miei dati seguano un Weibull e una distribuzione normale. Ma quale funzione di distribuzione descrive meglio i miei dati?


Facendo riferimento a elevendollar ho trovato il seguente codice, ma non so come interpretare i risultati:

fits <- list(no = fitdistr(mydata, "normal"),
             we = fitdistr(mydata, "weibull"))
sapply(fits, function(i) i$loglik)
       no        we 
-259.6540 -257.9268 

5
Perché vorresti capire quale distribuzione si adatta meglio ai tuoi dati?
Roland

6
Perché voglio generare numeri pseudo-casuali seguendo la distribuzione data.
tobibo

6
Non puoi usare KS per verificare se una distribuzione con parametri trovati dal set di dati corrisponde al set di dati. Vedi # 2 in questa pagina per esempio, oltre a alternative (e altri modi in cui il test KS può essere fuorviante).
tpg2114,

Un'altra discussione qui con esempi di codice su come applicare il test KS quando i parametri sono stimati dal campione.
Aksakal,

1
I used the fitdistr() function ..... che fitdistrfunzione è? Qualcosa da Excel? O qualcosa che ti sei scritto in C?
Lupi,

Risposte:


162

Innanzitutto, ecco alcuni brevi commenti:

  • I valori di un test di Kolmovorov-Smirnov (test KS) con parametri stimati saranno piuttosto errati. Quindi sfortunatamente, non puoi semplicemente adattare una distribuzione e quindi utilizzare i parametri stimati in un test di Kolmogorov-Smirnov per testare il tuo campione.p
  • Il tuo campione non seguirà mai esattamente una distribuzione specifica. Quindi anche se i tuoi valori dal KS-Test fossero validi e , significherebbe semplicemente che non puoi escludere che i tuoi dati seguano questa specifica distribuzione. Un'altra formulazione sarebbe che il tuo campione è compatibile con una certa distribuzione. Ma la risposta alla domanda "I miei dati seguono esattamente la distribuzione xy?" è sempre no.p>0.05
  • L'obiettivo qui non può essere quello di determinare con certezza quale distribuzione segue il campione. L'obiettivo è quello che @whuber (nei commenti) chiama descrizioni approssimative parsimoniose dei dati. Avere una specifica distribuzione parametrica può essere utile come modello dei dati.

Ma facciamo un po 'di esplorazione. Userò l'eccellente fitdistrpluspacchetto che offre alcune belle funzioni per l'adattamento della distribuzione. Useremo la funzione descdistper ottenere alcune idee sulle possibili distribuzioni dei candidati.

library(fitdistrplus)
library(logspline)

x <- c(37.50,46.79,48.30,46.04,43.40,39.25,38.49,49.51,40.38,36.98,40.00,
38.49,37.74,47.92,44.53,44.91,44.91,40.00,41.51,47.92,36.98,43.40,
42.26,41.89,38.87,43.02,39.25,40.38,42.64,36.98,44.15,44.91,43.40,
49.81,38.87,40.00,52.45,53.13,47.92,52.45,44.91,29.54,27.13,35.60,
45.34,43.37,54.15,42.77,42.88,44.26,27.14,39.31,24.80,16.62,30.30,
36.39,28.60,28.53,35.84,31.10,34.55,52.65,48.81,43.42,52.49,38.00,
38.65,34.54,37.70,38.11,43.05,29.95,32.48,24.63,35.33,41.34)

Ora usiamo descdist:

descdist(x, discrete = FALSE)

Descdist

La curtosi e l'asimmetria quadrata del tuo campione sono rappresentate come un punto blu chiamato "Osservazione". Sembra che le possibili distribuzioni includano la distribuzione di Weibull, Lognormal e possibilmente Gamma.

Adattiamo una distribuzione Weibull e una distribuzione normale:

fit.weibull <- fitdist(x, "weibull")
fit.norm <- fitdist(x, "norm")

Ora controlla l'adattamento per il normale:

plot(fit.norm)

Vestibilità normale

E per la calzata Weibull:

plot(fit.weibull)

Vestibilità Weibull

Entrambi sembrano buoni ma giudicati dal QQ-Plot, il Weibull forse sembra un po 'meglio, specialmente alle code. Di conseguenza, l'AIC dell'adattamento Weibull è inferiore rispetto all'adattamento normale:

fit.weibull$aic
[1] 519.8537

fit.norm$aic
[1] 523.3079

Simulazione del test di Kolmogorov-Smirnov

Userò la procedura di @Aksakal spiegata qui per simulare la statistica KS sotto zero.

n.sims <- 5e4

stats <- replicate(n.sims, {      
  r <- rweibull(n = length(x)
                , shape= fit.weibull$estimate["shape"]
                , scale = fit.weibull$estimate["scale"]
  )
  estfit.weibull <- fitdist(r, "weibull") # added to account for the estimated parameters
  as.numeric(ks.test(r
                     , "pweibull"
                     , shape= estfit.weibull$estimate["shape"]
                     , scale = estfit.weibull$estimate["scale"])$statistic
  )      
})

L'ECDF delle statistiche KS simulate è simile al seguente:

plot(ecdf(stats), las = 1, main = "KS-test statistic simulation (CDF)", col = "darkorange", lwd = 1.7)
grid()

Statistiche KS simulate

Infine, il nostro valore che utilizza la distribuzione nulla simulata delle statistiche KS è:p

fit <- logspline(stats)

1 - plogspline(ks.test(x
                       , "pweibull"
                       , shape= fit.weibull$estimate["shape"]
                       , scale = fit.weibull$estimate["scale"])$statistic
               , fit
)

[1] 0.4889511

Ciò conferma la nostra conclusione grafica che il campione è compatibile con una distribuzione Weibull.

Come spiegato qui , possiamo usare il bootstrap per aggiungere intervalli di confidenza puntuali al PDF o CDF Weibull stimato:

xs <- seq(10, 65, len=500)

true.weibull <- rweibull(1e6, shape= fit.weibull$estimate["shape"]
                         , scale = fit.weibull$estimate["scale"])

boot.pdf <- sapply(1:1000, function(i) {
  xi <- sample(x, size=length(x), replace=TRUE)
  MLE.est <- suppressWarnings(fitdist(xi, distr="weibull"))  
  dweibull(xs, shape=MLE.est$estimate["shape"],  scale = MLE.est$estimate["scale"])
}
)

boot.cdf <- sapply(1:1000, function(i) {
  xi <- sample(x, size=length(x), replace=TRUE)
  MLE.est <- suppressWarnings(fitdist(xi, distr="weibull"))  
  pweibull(xs, shape= MLE.est$estimate["shape"],  scale = MLE.est$estimate["scale"])
}
)   

#-----------------------------------------------------------------------------
# Plot PDF
#-----------------------------------------------------------------------------

par(bg="white", las=1, cex=1.2)
plot(xs, boot.pdf[, 1], type="l", col=rgb(.6, .6, .6, .1), ylim=range(boot.pdf),
     xlab="x", ylab="Probability density")
for(i in 2:ncol(boot.pdf)) lines(xs, boot.pdf[, i], col=rgb(.6, .6, .6, .1))

# Add pointwise confidence bands

quants <- apply(boot.pdf, 1, quantile, c(0.025, 0.5, 0.975))
min.point <- apply(boot.pdf, 1, min, na.rm=TRUE)
max.point <- apply(boot.pdf, 1, max, na.rm=TRUE)
lines(xs, quants[1, ], col="red", lwd=1.5, lty=2)
lines(xs, quants[3, ], col="red", lwd=1.5, lty=2)
lines(xs, quants[2, ], col="darkred", lwd=2)

CI_Density

#-----------------------------------------------------------------------------
# Plot CDF
#-----------------------------------------------------------------------------

par(bg="white", las=1, cex=1.2)
plot(xs, boot.cdf[, 1], type="l", col=rgb(.6, .6, .6, .1), ylim=range(boot.cdf),
     xlab="x", ylab="F(x)")
for(i in 2:ncol(boot.cdf)) lines(xs, boot.cdf[, i], col=rgb(.6, .6, .6, .1))

# Add pointwise confidence bands

quants <- apply(boot.cdf, 1, quantile, c(0.025, 0.5, 0.975))
min.point <- apply(boot.cdf, 1, min, na.rm=TRUE)
max.point <- apply(boot.cdf, 1, max, na.rm=TRUE)
lines(xs, quants[1, ], col="red", lwd=1.5, lty=2)
lines(xs, quants[3, ], col="red", lwd=1.5, lty=2)
lines(xs, quants[2, ], col="darkred", lwd=2)
#lines(xs, min.point, col="purple")
#lines(xs, max.point, col="purple")

CI_CDF


Raccordo di distribuzione automatica con GAMLSS

Il gamlsspacchetto per Roffre la possibilità di provare molte diverse distribuzioni e selezionare il "migliore" secondo il GAIC (il criterio di informazione Akaike generalizzato). La funzione principale è fitDist. Un'opzione importante in questa funzione è il tipo di distribuzioni che vengono provate. Ad esempio, l'impostazione type = "realline"proverà tutte le distribuzioni implementate definite sull'intera linea reale mentre type = "realsplus"tenterà solo le distribuzioni definite sulla linea positiva reale. Un'altra opzione importante è il parametro , che è la penalità per GAIC. Nell'esempio seguente, ho impostato il parametro che significa che la distribuzione "migliore" è selezionata secondo il classico AIC. Puoi impostare su qualsiasi cosa ti piaccia, come ad esempiokk=2klog(n) per il BIC.

library(gamlss)
library(gamlss.dist)
library(gamlss.add)

x <- c(37.50,46.79,48.30,46.04,43.40,39.25,38.49,49.51,40.38,36.98,40.00,
       38.49,37.74,47.92,44.53,44.91,44.91,40.00,41.51,47.92,36.98,43.40,
       42.26,41.89,38.87,43.02,39.25,40.38,42.64,36.98,44.15,44.91,43.40,
       49.81,38.87,40.00,52.45,53.13,47.92,52.45,44.91,29.54,27.13,35.60,
       45.34,43.37,54.15,42.77,42.88,44.26,27.14,39.31,24.80,16.62,30.30,
       36.39,28.60,28.53,35.84,31.10,34.55,52.65,48.81,43.42,52.49,38.00,
       38.65,34.54,37.70,38.11,43.05,29.95,32.48,24.63,35.33,41.34)

fit <- fitDist(x, k = 2, type = "realplus", trace = FALSE, try.gamlss = TRUE)

summary(fit)

*******************************************************************
Family:  c("WEI2", "Weibull type 2") 

Call:  gamlssML(formula = y, family = DIST[i], data = sys.parent()) 

Fitting method: "nlminb" 


Coefficient(s):
             Estimate  Std. Error  t value   Pr(>|t|)    
eta.mu    -24.3468041   2.2141197 -10.9962 < 2.22e-16 ***
eta.sigma   1.8661380   0.0892799  20.9021 < 2.22e-16 ***

Secondo l'AIC, la distribuzione di Weibull (in particolare WEI2una sua parametrizzazione speciale) si adatta meglio ai dati. L'esatta parametrizzazione della distribuzione WEI2è dettagliata in questo documento a pagina 279. Ispezioniamo l'adattamento osservando i residui in un diagramma a vite (sostanzialmente un diagramma QQ di tendenza):

WormPlot

Ci aspettiamo che i residui siano vicini alla linea orizzontale media e che il 95% di essi si trovi tra le curve punteggiate superiore e inferiore, che fungono da intervalli di confidenza puntuali del 95%. In questo caso, la trama del worm mi sta bene, indicando che la distribuzione di Weibull è adatta.


1
+1 Bella analisi. Una domanda, però. La conclusione positiva sulla compatibilità con una particolare distribuzione importante (Weibull, in questo caso) consente di escludere la possibilità di una distribuzione della miscela? Oppure dobbiamo eseguire un'analisi della miscela corretta e controllare GoF per escludere tale opzione?
Aleksandr Blekh,

18
@AleksandrBlekh È impossibile avere abbastanza potenza per escludere una miscela: quando la miscela è di due distribuzioni quasi identiche, non può essere rilevata e quando tutti i componenti tranne uno hanno proporzioni molto ridotte, non possono nemmeno essere rilevati. Tipicamente (in assenza di una teoria che potrebbe suggerire una forma distributiva), si adattano le distribuzioni parametriche al fine di ottenere descrizioni approssimative parsimoniose dei dati. Le miscele non sono nessuna di queste: richiedono troppi parametri e sono troppo flessibili allo scopo.
whuber

4
@whuber: +1 Apprezzo la tua eccellente spiegazione!
Aleksandr Blekh,

1
@Lourenco Ho guardato il grafico di Cullen e Fey. Il punto blu indica il nostro campione. Vedi che il punto è vicino alle linee di Weibull, Lognormal e Gamma (che è tra Weibull e Gamma). Dopo aver adattato ciascuna di queste distribuzioni, ho confrontato le statistiche di bontà di adattamento usando la funzione gofstate l'AIC. Non c'è consenso su quale sia il modo migliore per determinare la "migliore" distribuzione. Mi piacciono i metodi grafici e l'AIC.
COOLSerdash,

1
@Lourenco Intendi il lognormale? La distribuzione logistica (il segno "+") è abbastanza lontana dai dati osservati. Il lognormale sarebbe anche un candidato che normalmente guarderei. Per questo tutorial, ho scelto di non mostrarlo per mantenere il post breve. Il lognormale mostra un adattamento peggiore rispetto alla distribuzione Weibull e Normal. L'AIC è 537,59 e anche i grafici non sembrano troppo belli.
COOLSerdash,

15

Le trame sono per lo più un buon modo per avere un'idea migliore dell'aspetto dei tuoi dati. Nel tuo caso, consiglierei di tracciare la funzione di distribuzione cumulativa empirica (ecdf) rispetto ai cdfs teorici con i parametri ottenuti da fitdistr ().

L'ho fatto una volta per i miei dati e ho incluso anche gli intervalli di confidenza. Ecco l'immagine che ho ottenuto usando ggplot2 ().

inserisci qui la descrizione dell'immagine

La linea nera è la funzione di distribuzione cumulativa empirica e le linee colorate sono file PDF di diverse distribuzioni utilizzando i parametri che ho ottenuto utilizzando il metodo Maximum Likelihood. Si può facilmente vedere che la distribuzione esponenziale e normale non si adattano bene ai dati, perché le linee hanno una forma diversa rispetto all'ecdf e le linee sono abbastanza lontane dall'ecdf. Purtroppo le altre distribuzioni sono abbastanza vicine. Ma direi che la linea logNormal è la più vicina alla linea nera. Utilizzando una misura della distanza (ad esempio MSE) si potrebbe convalidare l'assunzione.

Se hai solo due distribuzioni concorrenti (ad esempio, scegli quelle che sembrano adattarsi meglio alla trama), puoi utilizzare un test del rapporto di verosimiglianza per verificare quali distribuzioni si adattano meglio.


20
Benvenuto in CrossValidated! La tua risposta potrebbe essere più utile se potessi modificarla per includere (a) il codice che hai usato per produrre l'immagine, e (b) come si leggerebbe l'immagine.
Stephan Kolassa,

2
Cosa viene tracciato lì? È una specie di trama dell'esponenzialità?
Glen_b

1
Ma come decidi quale distribuzione si adatta meglio ai tuoi dati? Solo secondo la grafica non sono riuscito a dirti se logNormal o weibull si adattano meglio ai tuoi dati.
tobibo

4
Se vuoi creare un generatore di numeri pseudo-casuali perché non usare il cdf empirico? Vuoi disegnare numeri che vanno oltre la tua distribuzione osservata?
elevendollar

6
Prendendo il tuo grafico al valore nominale, sembrerebbe che nessuna delle tue distribuzioni candidate si adatti perfettamente ai dati. Inoltre, il tuo ecdf sembra avere un asintoto orizzontale a meno di 0,03 che non ha senso, quindi non sono sicuro che sia davvero un ecdf in primo luogo.
Hong Ooi,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.