Answers:
Corsario在注释中提供了一个很好的解决方案:使用内核密度函数来测试是否包含在级别集中。
这个问题的另一种解释是,它要求一个程序来测试是否包含在由数据的二元正态近似所创建的椭圆中。首先,让我们生成一些看起来像问题中的插图的数据:
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))
椭圆由数据的第一和第二矩确定:
center <- apply(p, 2, mean)
sigma <- cov(p)
该公式需要方差-协方差矩阵的求逆:
sigma.inv = solve(sigma, matrix(c(1,0,0,1),2,2))
椭圆“高度”函数是二元法线密度的对数的负值:
ellipse <- function(s,t) {u<-c(s,t)-center; u %*% sigma.inv %*% u / 2}
(我忽略了等于的加性常数。)
为了测试这一点,让我们绘制一些轮廓。这需要在x和y方向上生成点网格:
n <- 50
x <- (0:(n-1)) * (500000/(n-1))
y <- (0:(n-1)) * (50000/(n-1))
在此网格上计算高度函数并绘制:
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)
显然,它可以工作。因此,确定点位于级别的椭圆轮廓内的测试为
ellipse(s,t) <= c
Mathematica的工作方式相同:计算数据的方差-协方差矩阵,将其求逆,构造ellipse
函数,然后一切就绪。
使用R包的ellipse()
功能,该图很简单mixtools
:
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")
您可以在Mathematica中尝试这种方法。
让我们生成一些双变量数据:
data = Table[RandomVariate[BinormalDistribution[{50, 50}, {5, 10}, .8]], {1000}];
然后我们需要加载这个包:
Needs["MultivariateStatistics`"]
现在:
ellPar=EllipsoidQuantile[data, {0.9}]
给出定义90%置信度椭圆的输出。从此输出获得的值采用以下格式:
{Ellipsoid[{x1, x2}, {r1, r2}, {{d1, d2}, {d3, d4}}]}
x1和x2指定椭圆的中心点,r1和r2指定半轴半径,d1,d2,d3和d4指定对齐方向。
您还可以绘制以下内容:
Show[{ListPlot[data, PlotRange -> {{0, 100}, {0, 100}}, AspectRatio -> 1], Graphics[EllipsoidQuantile[data, 0.9]]}]
椭圆的一般参数形式为:
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]}
您可以通过以下方式绘制它:
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}}]
您可以基于纯几何信息执行检查:如果椭圆中心(ellPar [[1,1]])与数据点之间的欧几里得距离大于椭圆中心与边界之间的距离椭圆(显然,在与点所在的方向相同的方向上),则该数据点在椭圆之外。
该方法基于平滑的内核分布。
这些是以与您的数据类似的方式分发的一些数据:
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];
我们在这些数据值上获得了平滑的内核分布:
skd = SmoothKernelDistribution[data];
我们为每个数据点获得一个数值结果:
eval = Table[{data[[i]], PDF[skd, data[[i]]]}, {i, Length[data]}];
我们确定一个阈值,然后选择所有高于此阈值的数据:
threshold = 1.2;
dataIn = Select[eval, #1[[2]] > threshold &][[All, 1]];
在这里,我们得到的数据不在该区域之内:
dataOut = Complement[data, dataIn];
现在我们可以绘制所有数据:
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]]
绿色点是高于阈值的那些点,红色点是低于阈值的那些点。
R包中的ellipse
函数ellipse
将生成这些椭圆(实际上是近似于椭圆的多边形)。您可以使用该椭圆。
实际上可能更容易的是计算您的点处的密度高度,然后看它是否比椭圆的轮廓值高(椭圆内)或更低(椭圆外)。该ellipse
函数内部使用的值,以创建椭圆,你可以寻找的高度,以使用从这里开始。
我在以下位置找到了答案:https : //stackoverflow.com/questions/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)