Come ottenere la regione dell'ellisse dai normali dati distribuiti bivariati?


11

Ho dei dati che assomigliano a:

figura

Ho provato ad applicare la distribuzione normale (la stima della densità del kernel funziona meglio, ma non ho bisogno di una precisione così grande) e funziona abbastanza bene. Il diagramma della densità crea un'ellisse.

Devo ottenere quella funzione dell'ellisse per decidere se un punto si trova all'interno della regione dell'ellisse o meno. Come farlo?

Il codice R o Mathematica è il benvenuto.

Risposte:


18

Corsario offre una buona soluzione in un commento: utilizzare la funzione di densità del kernel per verificare l'inclusione in un set di livelli.

Un'altra interpretazione della domanda è che richiede una procedura per verificare l'inclusione all'interno delle ellissi create da un'approssimazione normale bivariata ai dati. Per iniziare, generiamo alcuni dati che assomigliano all'illustrazione nella domanda:

library(mvtnorm) # References rmvnorm()
set.seed(17)
p <- rmvnorm(1000, c(250000, 20000), matrix(c(100000^2, 22000^2, 22000^2, 6000^2),2,2))

Le ellissi sono determinate dal primo e dal secondo momento dei dati:

center <- apply(p, 2, mean)
sigma <- cov(p)

La formula richiede l'inversione della matrice varianza-covarianza:

sigma.inv = solve(sigma, matrix(c(1,0,0,1),2,2))

La funzione "altezza" dell'ellisse è il negativo del logaritmo della densità normale bivariata :

ellipse <- function(s,t) {u<-c(s,t)-center; u %*% sigma.inv %*% u / 2}

log(2πdet(Σ))

Per provarlo , disegniamo alcuni dei suoi contorni. Ciò richiede la generazione di una griglia di punti nelle direzioni xey:

n <- 50
x <- (0:(n-1)) * (500000/(n-1))
y <- (0:(n-1)) * (50000/(n-1))

Calcola la funzione altezza su questa griglia e tracciala:

z <- mapply(ellipse, as.vector(rep(x,n)), as.vector(outer(rep(0,n), y, `+`)))
plot(p, pch=20, xlim=c(0,500000), ylim=c(0,50000), xlab="Packets", ylab="Flows")
contour(x,y,matrix(z,n,n), levels=(0:10), col = terrain.colors(11), add=TRUE)

Trama di contorno

Evidentemente funziona. Pertanto, il test per determinare se un punto trova all'interno di un contorno ellittico al livello è(S,t)c

ellipse(s,t) <= c

Mathematica fa il lavoro allo stesso modo: calcola la matrice varianza-covarianza dei dati, invertila, costruisci la ellipsefunzione e sei pronto.


Grazie a tutti, in particolare @whuber. Questo è esattamente ciò di cui ho bisogno.
matejuh,

Btw. esiste una soluzione semplice per i profili di stima della densità del kernel? Perché se voglio essere più rigoroso, i miei dati sembrano: github.com/matejuh/doschecker_wiki_images/raw/master/… resp. github.com/matejuh/doschecker_wiki_images/raw/master/…
matejuh

Non riesco a trovare una soluzione semplice in R. Considera l'utilizzo della funzione "SmoothKernelDistribution" di Mathematica 8.
whuber

2
I livelli corrispondono al livello di confidenza? Non la penso così. Come posso farlo per favore?
matejuh,

Ciò ha bisogno di una nuova domanda, perché è necessario specificare ciò di cui si cerca la fiducia e, a giudicare dalle proprie trame, ci sono dubbi sul fatto che tali ellissi siano descrizioni adeguate dei dati in primo luogo.
whuber

9

La trama è semplice con la ellipse()funzione del mixtoolspacchetto per R:

library(mixtools)
library(mvtnorm) 
set.seed(17)
p <- rmvnorm(1000, c(250000, 20000), matrix(c(100000^2, 22000^2, 22000^2, 6000^2),2,2))
plot(p, pch=20, xlim=c(0,500000), ylim=c(0,50000), xlab="Packets", ylab="Flows")
ellipse(mu=colMeans(p), sigma=cov(p), alpha = .05, npoints = 250, col="red") 

inserisci qui la descrizione dell'immagine


5

Primo approccio

Potresti provare questo approccio in Mathematica.

Generiamo alcuni dati bivariati:

data = Table[RandomVariate[BinormalDistribution[{50, 50}, {5, 10}, .8]], {1000}];

Quindi dobbiamo caricare questo pacchetto:

Needs["MultivariateStatistics`"]

E adesso:

ellPar=EllipsoidQuantile[data, {0.9}]

fornisce un output che definisce un'ellisse di confidenza al 90%. I valori ottenuti da questo output sono nel seguente formato:

{Ellipsoid[{x1, x2}, {r1, r2}, {{d1, d2}, {d3, d4}}]}

x1 e x2 specificano il punto in cui l'ellisse in posizione centrale, r1 e r2 specificano i raggi del semiasse e d1, d2, d3 e d4 specificano la direzione di allineamento.

Puoi anche tracciare questo:

Show[{ListPlot[data, PlotRange -> {{0, 100}, {0, 100}}, AspectRatio -> 1],  Graphics[EllipsoidQuantile[data, 0.9]]}]

La forma parametrica generale dell'ellisse è:

ell[t_, xc_, yc_, a_, b_, angle_] := {xc + a Cos[t] Cos[angle] - b Sin[t] Sin[angle],
    yc + a Cos[t] Sin[angle] + b Sin[t] Cos[angle]}

E puoi tracciarlo in questo modo:

ParametricPlot[
    ell[t, ellPar[[1, 1, 1]], ellPar[[1, 1, 2]], ellPar[[1, 2, 1]], ellPar[[1, 2, 2]],
    ArcTan[ellPar[[1, 3, 1, 2]]/ellPar[[1, 3, 1, 1]]]], {t, 0, 2 \[Pi]},
    PlotRange -> {{0, 100}, {0, 100}}]

È possibile eseguire un controllo basato su informazioni geometriche pure: se la distanza euclidea tra il centro dell'ellisse (ellPar [[1,1]]) e il punto dati è maggiore della distanza tra il centro dell'ellisse e il bordo di l'ellisse (ovviamente, nella stessa direzione in cui si trova il punto), quindi quel punto dati si trova all'esterno dell'ellisse.

Secondo approccio

Questo approccio si basa sulla distribuzione regolare del kernel.

Questi sono alcuni dati distribuiti in modo simile ai tuoi dati:

data1 = RandomVariate[BinormalDistribution[{.3, .7}, {.2, .3}, .8], 500];
data2 = RandomVariate[BinormalDistribution[{.6, .3}, {.4, .15}, .8], 500];
data = Partition[Flatten[Join[{data1, data2}]], 2];

Otteniamo una distribuzione uniforme del kernel su questi valori di dati:

skd = SmoothKernelDistribution[data];

Otteniamo un risultato numerico per ciascun punto dati:

eval = Table[{data[[i]], PDF[skd, data[[i]]]}, {i, Length[data]}];

Fissiamo una soglia e selezioniamo tutti i dati superiori a questa soglia:

threshold = 1.2;
dataIn = Select[eval, #1[[2]] > threshold &][[All, 1]];

Qui otteniamo i dati che non rientrano nella regione:

dataOut = Complement[data, dataIn];

E ora possiamo tracciare tutti i dati:

Show[ContourPlot[Evaluate@PDF[skd, {x, y}], {x, 0, 1}, {y, 0, 1}, PlotRange -> {{0, 1}, {0, 1}}, PlotPoints -> 50],
ListPlot[dataIn, PlotStyle -> Darker[Green]],
ListPlot[dataOut, PlotStyle -> Red]]

I punti di colore verde sono quelli sopra la soglia e i punti di colore rosso sono quelli sotto la soglia.

inserisci qui la descrizione dell'immagine


Grazie, il tuo secondo approccio mi aiuta molto con la distribuzione del kernel. Sono programmatore, non statistico e sono principiante in Mathmatica e R, quindi apprezzo molto il tuo aiuto. Nel tuo secondo approccio è chiaro per me come testare un punto in cui si trova. Ma come farlo nel primo approccio? Suppongo di dover confrontare il mio punto con la definizione dell'ellissoide. Puoi fornire per favore come? Ora devo sperare che ci siano le stesse definizioni in R, perché ho bisogno di usarlo in RinRuby ...
matejuh

@matejuh Ho appena aggiunto alcune righe in più sul primo approccio che potrebbe indirizzarti verso una soluzione.
VLC

2

La ellipsefunzione nel ellipsepacchetto per R genererà queste ellissi (in realtà un poligono che si avvicina all'ellisse). Potresti usare quell'ellisse.

ellipseχ2


1

Ho trovato la risposta su: /programming/2397097/how-can-a-data-ellipse-be-superimposed-on-a-ggplot2-scatterplot

#bootstrap
set.seed(101)
n <- 1000
x <- rnorm(n, mean=2)
y <- 1.5 + 0.4*x + rnorm(n)
df <- data.frame(x=x, y=y, group="A")
x <- rnorm(n, mean=2)
y <- 1.5*x + 0.4 + rnorm(n)
df <- rbind(df, data.frame(x=x, y=y, group="B"))

#calculating ellipses
library(ellipse)
df_ell <- data.frame()
for(g in levels(df$group)){
df_ell <- rbind(df_ell, cbind(as.data.frame(with(df[df$group==g,], ellipse(cor(x, y), 
                                         scale=c(sd(x),sd(y)), 
                                         centre=c(mean(x),mean(y))))),group=g))
}
#drawing
library(ggplot2)
p <- ggplot(data=df, aes(x=x, y=y,colour=group)) + geom_point(size=1.5, alpha=.6) +
  geom_path(data=df_ell, aes(x=x, y=y,colour=group), size=1, linetype=2)

inserisci qui la descrizione dell'immagine

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.