Pourcentage de régions qui se chevauchent de deux distributions normales

46

Je me demandais, étant donné deux distributions normales avec et σ 2 , μ 2σ1, μ1σ2, μ2

  • Comment puis-je calculer le pourcentage de régions qui se chevauchent de deux distributions?
  • Je suppose que ce problème a un nom spécifique, connaissez-vous un nom particulier décrivant ce problème?
  • Êtes-vous au courant de la mise en œuvre de ceci (par exemple, du code Java)?
Ali Salehi
la source
2
Que voulez-vous dire par région superposée? Voulez-vous dire la zone qui est en dessous des deux courbes de densité?
Nick Sabbe
Je veux dire l'intersection de deux zones
Ali Salehi
4
En bref, en écrivant les deux pdfs en tant que et g , voulez-vous vraiment calculer min ( f ( x ) , g ( x ) ) d x ? Pourriez-vous nous éclairer sur le contexte dans lequel cela se produit et comment il serait interprété? fgmin(f(x),g(x))dx
whuber

Réponses:

41

C'est ce que l'on appelle souvent le "coefficient de recouvrement" (OVL). Googler pour cela vous donnera beaucoup de succès. Vous pouvez trouver un nomogramme pour le cas bi-normal ici . Un article utile peut être:

  • Henry F. Inman; Edwin L. Bradley Jr (1989). Le coefficient de chevauchement sert de mesure d’accord entre les distributions de probabilité et l’estimation ponctuelle du chevauchement de deux densités normales. Communications en statistique - Théorie et méthodes, 18 (10), 3851-3874. ( Lien )

Modifier

Maintenant, cela m’intéresse davantage, j’ai donc décidé de créer du code R pour le calculer (c’est une intégration simple). J'ai jeté dans un graphique des deux distributions, y compris l'ombrage de la région qui se chevauchent:

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)

Pour cet exemple, le résultat est: 0.6099324avec erreur absolue < 1e-04. Figure ci-dessous.

Exemple

Wolfgang
la source
10
(+1) Google recherche au moins trois définitions distinctes (Matsushita, Morisita et Weitzman). Votre implémentation est celle de Weitzman.
whuber
1
0.60993 24 est une approximation de 0.60993 43398 78944 33895 ....
whuber
10

Ceci est donné par le coefficient de Bhattacharyya . Pour les autres distributions, voir aussi la version généralisée, la distance de Hellinger entre deux distributions.

Je ne connais aucune bibliothèque pour calculer cela, mais étant donné la formulation explicite en termes de distances de Mahalanobis et de déterminant de matrices de variance, la mise en œuvre ne devrait pas poser de problème.

utilisateur603
la source
3
Le coefficient de Bhattacharyya est une mesure du chevauchement, mais ce n'est pas la même chose, n'est-ce pas?
Stéphane Laurent le
7

Je ne sais pas s'il existe un moyen standard évident de le faire, mais:

Tout d'abord, vous trouvez les points d'intersection entre les deux densités. Ceci peut être facilement réalisé en égalisant les deux densités, ce qui, pour la distribution normale, devrait aboutir à une équation quadratique pour x.

(xμ2)22σ22(xμ1)22σ12=logσ1σ2

Cela peut être résolu avec un calcul de base.

Ainsi, vous avez soit zéro, un ou deux points d'intersection. Maintenant, ces points d'intersection divisent la ligne réelle en 1, 2 ou trois parties, l'une des deux densités étant la plus faible. Si rien de plus mathématique ne vous vient à l’esprit, essayez un point quelconque dans l’une des parties pour trouver laquelle est la plus basse.

Votre valeur d'intérêt est maintenant la somme des zones situées sous la courbe de densité la plus faible de chaque partie. Cette zone peut maintenant être trouvée à partir de la fonction de distribution cumulative (il suffit de soustraire la valeur dans les deux bords de la «partie».

Nick Sabbe
la source
4
σ1σ2μ1μ2σ1=σ2
2
@ Whuber Pourriez-vous transformer cela en une réponse complète? Ou peut-être que Nick peut éditer le sien.
Aleksandr Dubinsky
σ1σ2μ1μ2
@ Stéphane Je pense que vous avez raison de dire que l'ordre de priorité est déterminé par la SD: la densité avec une SD plus petite aura éventuellement des queues plus petites dans les directions positive et négative et aura donc les valeurs les plus grandes entre les zéros et les valeurs plus petites ailleurs.
whuber
@ whuber Oui, et il est en effet facile de voir que l'ordre des SD détermine le signe du coefficient du 2nd ordre du polynome dérivé par Nick.
Stéphane Laurent
1

Pour la postérité, la solution de wolfgang n'a pas fonctionné pour moi: j'ai rencontré des bugs dans la integratefonction. Je l'ai donc combiné avec la réponse de Nick Staubbe pour développer la petite fonction suivante. Devrait être plus rapide et moins complexe que l’intégration numérique:

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
}
utilisateur_générique
la source
ne devrait-il pas revenir (l+r)/2?
RSHAP le
0

Voici la version 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;

}
Vithun Venugopalan
la source
0

Je pense que quelque chose comme ceci pourrait être la solution dans 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) 

Au moins, je pourrais reproduire la valeur 0,8026 donnée ci-dessous Fig.1 dans ce pdf .

Vous devez simplement adapter les valeurs de début et de fin et les intervalles pour être précis, car il ne s'agit que d'une solution numérique.

Danny K
la source