Percentuale di regioni sovrapposte di due distribuzioni normali


46

Mi chiedevo, date due distribuzioni normali con eσ1, μ1σ2, μ2

  • come posso calcolare la percentuale di regioni sovrapposte di due distribuzioni?
  • Suppongo che questo problema abbia un nome specifico, sei a conoscenza di qualche nome particolare che descriva questo problema?
  • Sei a conoscenza di un'implementazione di questo (ad esempio, codice Java)?

2
Cosa intendi con regione sovrapposta? Intendi l'area che si trova al di sotto di entrambe le curve di densità?
Nick Sabbe,

Intendo l'intersezione di due aree
Ali Salehi,

4
In breve, la scrittura dei due file PDF come e , vuoi veramente calcolare ? Potresti illuminarci sul contesto in cui ciò si presenta e su come sarebbe interpretato? fgmin(f(X),g(X))dX
whuber

Risposte:


41

Questo è anche spesso chiamato "coefficiente di sovrapposizione" (OVL). Cercare su Google per questo ti darà molti successi. Puoi trovare un nomogramma per il caso bi-normale qui . Un documento utile può essere:

  • Henry F. Inman; Edwin L. Bradley Jr (1989). Il coefficiente di sovrapposizione come misura di accordo tra le distribuzioni di probabilità e la stima puntuale della sovrapposizione di due densità normali. Communications in Statistics - Theory and Methods, 18 (10), 3851-3874. ( Link )

modificare

Ora mi hai interessato di più a questo, quindi sono andato avanti e ho creato il codice R per calcolare questo (è una semplice integrazione). Ho gettato una trama delle due distribuzioni, inclusa l'ombreggiatura della regione sovrapposta:

min.f1f2 <- function(x, mu1, mu2, sd1, sd2) {
    f1 <- dnorm(x, mean=mu1, sd=sd1)
    f2 <- dnorm(x, mean=mu2, sd=sd2)
    pmin(f1, f2)
}

mu1 <- 2;    sd1 <- 2
mu2 <- 1;    sd2 <- 1

xs <- seq(min(mu1 - 3*sd1, mu2 - 3*sd2), max(mu1 + 3*sd1, mu2 + 3*sd2), .01)
f1 <- dnorm(xs, mean=mu1, sd=sd1)
f2 <- dnorm(xs, mean=mu2, sd=sd2)

plot(xs, f1, type="l", ylim=c(0, max(f1,f2)), ylab="density")
lines(xs, f2, lty="dotted")
ys <- min.f1f2(xs, mu1=mu1, mu2=mu2, sd1=sd1, sd2=sd2)
xs <- c(xs, xs[1])
ys <- c(ys, ys[1])
polygon(xs, ys, col="gray")

### only works for sd1 = sd2
SMD <- (mu1-mu2)/sd1
2 * pnorm(-abs(SMD)/2)

### this works in general
integrate(min.f1f2, -Inf, Inf, mu1=mu1, mu2=mu2, sd1=sd1, sd2=sd2)

Per questo esempio, il risultato è: 0.6099324con errore assoluto < 1e-04. Figura sotto.

Esempio


10
(+1) Google cerca almeno tre definizioni distinte (Matsushita, Morisita e Weitzman). La tua implementazione è di Weitzman.
whuber

1
0.60993 24 è un'approssimazione per 0.60993 43398 78944 33895 ....
whuber

10

Questo è dato dal coefficiente di Bhattacharyya . Per altre distribuzioni, vedere anche la versione generalizzata, la distanza di Hellinger tra due distribuzioni.

Non conosco alcuna biblioteca per calcolare questo, ma data la formulazione esplicita in termini di distanze di Mahalanobis e determinante delle matrici di varianza, l'implementazione non dovrebbe essere un problema.


3
Il coefficiente di Bhattacharyya è una misura di sovrapposizione ma non è lo stesso, vero?
Stéphane Laurent,

7

Non so se esiste un modo standard ovvio per farlo, ma:

Innanzitutto, trovi i punti di intersezione tra le due densità. Ciò può essere facilmente ottenuto equiparando entrambe le densità, che, per la distribuzione normale, dovrebbero comportare un'equazione quadratica per x.

(X-μ2)22σ22-(X-μ1)22σ12=logσ1σ2

Questo può essere risolto con il calcolo di base.

Quindi hai zero, uno o due punti di intersezione. Ora, questi punti di intersezione dividono la linea reale in 1, 2 o tre parti, dove una delle due densità è la più bassa. Se non viene in mente nulla di più matematico, prova qualsiasi punto all'interno di una delle parti per trovare qual è la più bassa.

Il tuo valore di interesse è ora la somma delle aree sotto la curva di densità più bassa in ogni parte. Quest'area può ora essere trovata dalla funzione di distribuzione cumulativa (basta sottrarre il valore in entrambi i bordi della 'parte'.


4
σ1σ2μ1μ2σ1=σ2

2
@whuber Potresti trasformarlo in una risposta completa? O forse Nick può modificare il suo.
Aleksandr Dubinsky,

σ1σ2μ1μ2

@ Stéphane Penso che tu abbia ragione nel dire che le SD determinano l'ordine: la densità con SD più piccole alla fine avrà code più piccole sia in direzione positiva che negativa e quindi avrà valori più grandi tra gli zeri e valori più piccoli altrove.
whuber

@whuber Sì, e in effetti è facile vedere che l'ordine delle SD determina il segno del coefficiente del 2 ° ordine del polinomio derivato da Nick.
Stéphane Laurent,

1

Per i posteri, la soluzione di Wolfgang non ha funzionato per me: mi sono imbattuto in bug nella integratefunzione. Così l'ho combinato con la risposta di Nick Staubbe per sviluppare la seguente piccola funzione. Dovrebbe essere più veloce e meno difettoso rispetto all'uso dell'integrazione numerica:

get_overlap_coef <- function(mu1, mu2, sd1, sd2){
  xs  <- seq(min(mu1 - 4*sd1, mu2 - 4*sd2), 
             max(mu1 + 4*sd1, mu2 + 4*sd2), 
             length.out = 500)
  f1  <- dnorm(xs, mean=mu1, sd=sd1)
  f2  <- dnorm(xs, mean=mu2, sd=sd2)
  int <- xs[which.max(pmin(f1, f2))]
  l   <- pnorm(int, mu1, sd1, lower.tail = mu1>mu2)
  r   <- pnorm(int, mu2, sd2, lower.tail = mu1<mu2)
  l+r
}

non dovrebbe tornare (l+r)/2?
RSHAP,

0

Ecco la versione Java, Apache Commons Mathematics Library :

import org.apache.commons.math3.distribution.NormalDistribution;

public static double overlapArea(double mean1, double sd1, double mean2, double sd2) {

    NormalDistribution normalDistribution1 = new NormalDistribution(mean1, sd1);
    NormalDistribution normalDistribution2 = new NormalDistribution(mean2, sd2);

    double min = Math.min(mean1 - 6 * sd1, mean2 - 6 * sd2);
    double max = Math.max(mean1 + 6 * sd1, mean2 + 6 * sd2);
    double range = max - min;

    int resolution = (int) (range/Math.min(sd1, sd2));

    double partwidth = range / resolution;

    double intersectionArea = 0;

    int begin = (int)((Math.max(mean1 - 6 * sd1, mean2 - 6 * sd2)-min)/partwidth);
    int end = (int)((Math.min(mean1 + 6 * sd1, mean2 + 6 * sd2)-min)/partwidth);

    /// Divide the range into N partitions
    for (int ii = begin; ii < end; ii++) {

        double partMin = partwidth * ii;
        double partMax = partwidth * (ii + 1);

        double areaOfDist1 = normalDistribution1.probability(partMin, partMax);
        double areaOfDist2 = normalDistribution2.probability(partMin, partMax);

        intersectionArea += Math.min(areaOfDist1, areaOfDist2);
    }

    return intersectionArea;

}

0

Penso che qualcosa del genere potrebbe essere la soluzione in MATLAB:

[overlap] = calc_overlap_twonormal(2,2,0,1,-20,20,0.01)

% numerical integral of the overlapping area of two normal distributions:
% s1,s2...sigma of the normal distributions 1 and 2
% mu1,mu2...center of the normal distributions 1 and 2
% xstart,xend,xinterval...defines start, end and interval width
% example: [overlap] = calc_overlap_twonormal(2,2,0,1,-10,10,0.01)

function [overlap2] = calc_overlap_twonormal(s1,s2,mu1,mu2,xstart,xend,xinterval)

clf
x_range=xstart:xinterval:xend;
plot(x_range,[normpdf(x_range,mu1,s1)' normpdf(x_range,mu2,s2)']);
hold on
area(x_range,min([normpdf(x_range,mu1,s1)' normpdf(x_range,mu2,s2)']'));
overlap=cumtrapz(x_range,min([normpdf(x_range,mu1,s1)' normpdf(x_range,mu2,s2)']'));
overlap2 = overlap(end);

[overlap] = calc_overlap_twonormal(2,2,0,1,-10,10,0.01) 

Almeno potrei riprodurre il valore 0.8026 riportato di seguito in Fig.1 in questo pdf .

Devi solo adattare i valori di inizio e fine e intervallo per essere precisi in quanto questa è solo una soluzione numerica.

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.