Un método alternativo para la estimación empírica es utilizar la tecnología ROC (Receiver Operating Curve) para la estimación. El umbral de Youden nos proporciona una estimación empírica del principal punto de intersección (véase https://journals.lww.com/epidem/Fulltext/2005/01000/Optimal_Cut_point_and_Its_Corresponding_Youden.11.aspx y https://math.stackexchange.com/questions/2404750/intersection-normal-distributions-and-minimal-decision-error/2435957#2435957 ).
El umbral de Youden es el umbral en el que se maximiza la suma de la sensibilidad y la especificidad de la prueba y se minimiza la suma de las tasas de error (tasa de falsos positivos y tasa de falsos negativos). El solapamiento es igual a esta suma mínima de tasas de error.
library(UncertainInterval)
simple_roc2 <- function(ref, test){
tab = table(test, ref) # head(tab)
data.frame(threshold=paste('>=',rownames(tab)),
ref0 = tab[,1],
ref1 = tab[,2],
FPR = rev(cumsum(rev(tab[,1])/sum(tab[,1]))), # 1-Sp
TPR = rev(cumsum(rev(tab[,2])/sum(tab[,2]))), # Se
row.names=1:nrow(tab))
}
a <- rnorm(10000)
b <- rnorm(10000, 2)
test=c(a,b)
ref=c(rep(0, length(a)), rep(1, length(b)))
# table(test, ref)
res = simple_roc2(ref, test)
res$FNR = 1-res$TPR # 1-Se
pos.optimal.threshold = which.min(res$FPR+res$FNR)
optimal.threshold=row.names(table(test, ref))[pos.optimal.threshold] # Youden threshold
plotMD(ref, test) # library(UncertainInterval) # includes kernel intersection estimate
abline(v=optimal.threshold, col='red')
overlap1(a, b)
(overlap2 = min(res$FPR+res$FNR))
En este caso, esta estimación no paramétrica tiene una ligera tendencia a subestimar el valor real. Esta técnica roc sólo maneja un único punto de intersección (principal). No depende de ninguna distribución específica. Asegúrese de que la distribución b tiene los valores más altos (media(b) > media(a)).
Observando repetidamente los gráficos producidos por plotMD se observa que con 2 * 100 casos el solapamiento de la muestra difiere considerablemente. La mayoría de las diferencias se deben a diferencias de muestra, pero, dependiendo de las distribuciones, todos los métodos tienen condiciones en las que no funcionan correctamente. El uso de un kernel de densidad gaussiana es sensible a los picos en los datos, que pueden ser subestimados. Los métodos de densidad kernel dependen de los parámetros de ajuste que se den a la función de densidad. El método roc no tiene parámetros, pero asume un único punto de intersección. En consecuencia, puede sobrestimar el solapamiento cuando hay un punto de intersección adicional (el punto crítico es la presencia de más de un punto de intersección, no la varianza). Esta sobreestimación puede ser insignificante cuando este punto de intersección secundario se encuentra en las colas de ambas distribuciones.
¿Cómo dar sentido a los distintos métodos y sugerencias? Idear una prueba es más sencillo cuando conocemos el valor verdadero de dos distribuciones. El valor verdadero del solapamiento de las dos distribuciones normales es fácil de calcular. El punto de intersección es simplemente la media de las dos medias de las distribuciones, ya que tienen igual varianza: 1. El solapamiento verdadero es entonces 0,3173105:
(true.overlap = pnorm(1,2,1)+ 1-pnorm(1,0,1))
Véase https://stackoverflow.com/questions/16982146/point-of-intersection-2-normal-curves/45184024#45184024 para un método general de cálculo del punto de intersección de dos distribuciones normales.
En el problema original, hay una mezcla de distribución normal y uniforme. El valor verdadero está en ese caso:
true.value=sum(pmin(diff(pnorm(0:3)),1/3))
Una simulación puede mostrarnos qué método de estimación se aproxima más al valor real:
library(sfsmisc)
overlap1 <- function(a,b){
lower <- min(c(a, b)) - 1
upper <- max(c(a, b)) + 1
# generate kernel densities
da <- density(a, from=lower, to=upper)
db <- density(b, from=lower, to=upper)
d <- data.frame(x=da$x, a=da$y, b=db$y)
# calculate intersection densities
d$w <- pmin(d$a, d$b)
# integrate areas under curves
total <- integrate.xy(d$x, d$a) + integrate.xy(d$x, d$b)
intersection <- integrate.xy(d$x, d$w)
# compute overlap coefficient
2 * intersection / total
}
library(overlap)
library(scales)
# For explanation of the next function see the answer of S. Venne
overlapEstimates =function(a, b){
a = data.frame( value = a, Source = "a" )
b = data.frame( value = b, Source = "b" )
d = rbind(a, b)
d$value <- scales::rescale( d$value, to = c(0,2*pi) )
a <- d[d$Source == "a", 1]
b <- d[d$Source == "b", 1]
overlapEst(a, b, kmax = 3, adjust=c(0.8, 1, 4), n.grid = 500)
}
nsim=1000; nobs=100; m1=4; sd1=1; m2=6; sd2=1; poi=5
(true.overlap= 1-pnorm(poi, m1, sd1)+pnorm(poi,m2,sd2))
out=matrix(NA,nrow=nsim,ncol=4)
set.seed(0)
for (i in 1:nsim){
x <- rnorm( nobs, m1, sd1 )
y <- rnorm( nobs, m2, sd2 )
out[i,1] = overlap1(x,y)
out[i,2] = overlapping::overlap(list( x = x, y = y ))$OV
out[i,3] = overlapEstimates(x,y)['Dhat4']
out[i,4] = roc.overlap(x,y)
}
(true.overlap=pnorm(poi,m2,sd2)+1-pnorm(poi,m1,sd1))
colMeans(out-true.overlap) # estimation errors
apply(out, 2, sd) # # sd of the estimation errors
apply(out, 2, range)-true.overlap
par(mfrow=c(2,2))
br = seq(-.33,+.33,by=0.05)
hist(out[,1]-true.overlap, breaks=br, ylim=c(0,500),
xlim=c(-.33,.33), main='overlap1');
abline(v=0, col='red')
hist(out[,2]-true.overlap, breaks=br, ylim=c(0,500),
xlim=c(-.33,.33), main='overlapping::overlap')
abline(v=0, col='red')
hist(out[,3]-true.overlap, breaks=br, ylim=c(0,600),
xlim=c(-.33,.33), main='overlap::overlapEst')
abline(v=0, col='red')
hist(out[,4]-true.overlap, breaks=br, ylim=c(0,500),
xlim=c(-.33,.33), main="ROC estimate");
abline(v=0, col='red')
En este caso, especialmente la función overlapping::overlap tiene una tendencia a la (ligera) subestimación, mientras que overlap1 muestra el menor error de estimación. Las estimaciones que utilizan la función de densidad de un modo u otro, pueden producir mejores o peores resultados dependiendo de los parámetros dados a la función de densidad. El método roc no tiene parámetros, lo que puede ser una ventaja.
Siempre es aconsejable observar detenidamente un gráfico de las distribuciones solapadas e idear un método de prueba pertinente para comprobar si la técnica de estimación del solapamiento funciona como se espera para el tipo de datos que se tiene. Es preferible no utilizar técnicas que produzcan sistemáticamente estimaciones demasiado bajas o demasiado altas.