[英]R: Find maximum of density plot
我有大约 25,000 行myData
的数据,其中列attr
的值从 0 -> 45,600。 我不确定如何制作简化或可重现的数据...
无论如何,我正在绘制attr
的密度,如下所示,我还找到了密度最大的attr
值:
library(ggplot)
max <- which.max(density(myData$attr)$y)
density(myData$attr)$x[max]
ggplot(myData, aes(x=attr))+
geom_density(color="darkblue", fill="lightblue")+
geom_vline(xintercept = density(myData$attr)$x[max])+
xlab("attr")
由于数据是倾斜的,因此我尝试通过将scale_x_log10()
添加到ggplot
来以对数比例绘制 x 轴,这是新图:
我现在的问题是:
1.为什么现在最高2分? 为什么我的 x 截距不再位于最大点?
2.如何找到 2 个新的最大点的截距?
最后,我尝试将 y 轴转换为count
:
ggplot(myData, aes(x=attr)) +
stat_density(aes(y=..count..), color="black", fill="blue", alpha=0.3)+
xlab("attr")+
scale_x_log10()
3.如何找到 2 个峰值的count
?
为了让我的评论更全面,ggplot 在进行密度估计之前先记录日志,这会导致形状差异,因为分箱覆盖了域的不同部分。 例如,
(bins <- seq(1, 10, length.out = 10))
#> [1] 1 2 3 4 5 6 7 8 9 10
(bins_log <- 10^seq(log10(1), log10(10), length.out = 10))
#> [1] 1.000000 1.291550 1.668101 2.154435 2.782559 3.593814 4.641589
#> [8] 5.994843 7.742637 10.000000
library(ggplot2)
ggplot(data.frame(x = c(bins, bins_log),
trans = rep(c('identity', 'log10'), each = 10)),
aes(x, y = trans, col = trans)) +
geom_point()
这种分箱会影响最终的密度形状。 例如,比较未转换的密度:
d <- density(mtcars$disp)
plot(d)
到预先记录的一个:
d_log <- density(log10(mtcars$disp))
plot(d_log)
请注意,模式的高度会翻转,我相信您要的是第一个,但是在密度之后应用了对数变换。 IE
d_x_log <- d
d_x_log$x <- log10(d_x_log$x)
plot(d_x_log)
这里的模式是相似的,只是被压缩了。
移至 ggplot 时,要在对数转换之前进行密度估计,最简单的方法是事先在 ggplot 之外进行:
library(ggplot2)
d <- density(mtcars$disp)
ggplot(data.frame(x = d$x, y = d$y), aes(x, y)) +
geom_density(stat = "identity", fill = 'burlywood', alpha = 0.3) +
scale_x_log10()
当只有一个模式时找到模式相对容易; 它只是d$x[which.max(d$x)]
。 但是当您有多种模式时,这还不够好,因为它只会显示最高的模式。 一种解决方案是有效地求导并寻找斜率从正变为负的位置。 我们可以用diff
以数字方式执行此操作,并且由于我们只关心结果是正数还是负数,因此在其上sign
以将所有内容变为 -1 和 1。* 如果我们在that上调用diff
,除最大值外,所有内容都将为 0和最小值,分别为 -2 和 2。 然后我们可以查找which
值小于 0,我们可以使用它来进行子集化。 (因为diff
没有在末尾插入NA
,所以您必须在索引中添加一个。)总而言之,设计用于密度 object,
d <- density(mtcars$disp)
modes <- function(d){
i <- which(diff(sign(diff(d$y))) < 0) + 1
data.frame(x = d$x[i], y = d$y[i])
}
modes(d)
#> x y
#> 1 128.3295 0.003100294
#> 2 305.3759 0.002204658
d$x[which.max(d$y)] # double-check
#> [1] 128.3295
我们可以将它们添加到我们的 plot 中,它们会得到很好的转换:
ggplot(data.frame(x = d$x, y = d$y), aes(x, y)) +
geom_density(stat = "identity", fill = 'mistyrose', alpha = 0.3) +
geom_vline(xintercept = modes(d)$x) +
scale_x_log10()
要将 y 轴转换为计数而不是密度,请将 y 乘以观察次数,观察次数以n
形式存储在密度 object 中:
ggplot(data.frame(x = d$x, y = d$y * d$n), aes(x, y)) +
geom_density(stat = "identity", fill = 'thistle', alpha = 0.3) +
geom_vline(xintercept = modes(d)$x) +
scale_x_log10()
在这种情况下,它看起来有点傻,因为只有 32 个观测值分布在一个宽域中,但是对于更大的 n 和更小的域,它更易于解释:
d <- density(diamonds$carat, n = 2048)
ggplot(data.frame(x = d$x, y = d$y * d$n), aes(x, y)) +
geom_density(stat = "identity", fill = 'papayawhip', alpha = 0.3) +
geom_point(data = modes(d), aes(y = y * d$n)) +
scale_x_log10()
* 如果值正好为 0,则为 0,但这在这里不太可能并且无论如何都可以正常工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.