在两个点之间为核密度图进行阴影处理。

101

我经常使用核密度图来说明分布情况。在R中,创建这些图很容易且快速,如下所示:

set.seed(1)
draws <- rnorm(100)^2
dens <- density(draws)
plot(dens)
#or in one line like this: plot(density(rnorm(100)^2))

这给了我一个漂亮的小PDF:

输入图像描述

我想要将该PDF从第75个百分位到第95个百分位之间的区域进行阴影处理。使用quantile 函数很容易计算出这些点:

q75 <- quantile(draws, .75)
q95 <- quantile(draws, .95)

我该如何为q75q95之间的区域添加阴影?


你能提供一下如何在范围的外部和内部进行着色的例子吗?谢谢。 - Milktrader
5个回答

77

使用polygon()函数,请参见其帮助页面,我相信我们这里也有类似的问题。

您需要找到分位数值的索引才能获得实际的(x,y)对。

编辑:在这里:

x1 <- min(which(dens$x >= q75))  
x2 <- max(which(dens$x <  q95))
with(dens, polygon(x=c(x[c(x1,x1:x2,x2)]), y= c(0, y[x1:x2], 0), col="gray"))

输出结果(由JDL添加)

在此输入图像描述


3
如果你没有提供结构,我永远不可能让这个工作起来。谢谢! - JD Long
2
这是那种自古以来就存在于demo(graphics)中的东西,所以偶尔会遇到。NBER回归阴影等也是同样的想法。 - Dirk Eddelbuettel
1
哦,我知道我在哪里看到过它,但是无法从我的脑索引中找出来。我很高兴你的脑索引比我的好。 - JD Long

74

另一个解决方案:

dd <- with(dens,data.frame(x,y))

library(ggplot2)

qplot(x,y,data=dd,geom="line")+
  geom_ribbon(data=subset(dd,x>q75 & x<q95),aes(ymax=y),ymin=0,
              fill="red",colour=NA,alpha=0.5)

结果:

alt text


24

一个更加详细的解决方案:

如果你想要着色两个尾部(复制并粘贴Dirk的代码)并且使用已知的x值:

set.seed(1)
draws <- rnorm(100)^2
dens <- density(draws)
plot(dens)

q2     <- 2
q65    <- 6.5
qn08   <- -0.8
qn02   <- -0.2

x1 <- min(which(dens$x >= q2))  
x2 <- max(which(dens$x <  q65))
x3 <- min(which(dens$x >= qn08))  
x4 <- max(which(dens$x <  qn02))

with(dens, polygon(x=c(x[c(x1,x1:x2,x2)]), y= c(0, y[x1:x2], 0), col="gray"))
with(dens, polygon(x=c(x[c(x3,x3:x4,x4)]), y= c(0, y[x3:x4], 0), col="gray"))

结果:

双尾多项式


我有PNG文件并将其托管在免费图像托管上,但它可能无法加载,因为......我不确定。 - Milktrader
非常模糊的文件。能否请您重新制作并直接在此处上传?Stack Overflow有自己的服务器服务吗? - Dirk Eddelbuettel
很抱歉,我不知道如何直接上传到 Stack Overflow。 - Milktrader

21
这个问题需要一个“格子”答案。以下是一个非常基本的答案,只需简单地调整Dirk和其他人所采用的方法:
#Set up the data
set.seed(1)
draws <- rnorm(100)^2
dens <- density(draws)

#Put in a simple data frame   
d <- data.frame(x = dens$x, y = dens$y)

#Define a custom panel function;
# Options like color don't need to be hard coded    
shadePanel <- function(x,y,shadeLims){
    panel.lines(x,y)
    m1 <- min(which(x >= shadeLims[1]))
    m2 <- max(which(x <= shadeLims[2]))
    tmp <- data.frame(x1 = x[c(m1,m1:m2,m2)], y1 = c(0,y[m1:m2],0))
    panel.polygon(tmp$x1,tmp$y1,col = "blue")
}

#Plot
xyplot(y~x,data = d, panel = shadePanel, shadeLims = c(1,3))

enter image description here


4
这是另一种基于函数近似核密度的 ggplot2 变体:

approxdens <- function(x) {
    dens <- density(x)
    f <- with(dens, approxfun(x, y))
    f(x)
}

使用原始数据(而不是生成具有密度估计的x和y值的新数据框)的好处在于,它还适用于分面图,其中分位数值取决于按哪个变量对数据进行分组:

所使用的代码

library(tidyverse)
library(RColorBrewer)

# dummy data
set.seed(1)
n <- 1e2
dt <- tibble(value = rnorm(n)^2)

# function that approximates the density at the provided values
approxdens <- function(x) {
    dens <- density(x)
    f <- with(dens, approxfun(x, y))
    f(x)
}

probs <- c(0.75, 0.95)

dt <- dt %>%
    mutate(dy = approxdens(value),                         # calculate density
           p = percent_rank(value),                        # percentile rank 
           pcat = as.factor(cut(p, breaks = probs,         # percentile category based on probs
                                include.lowest = TRUE)))

ggplot(dt, aes(value, dy)) +
    geom_ribbon(aes(ymin = 0, ymax = dy, fill = pcat)) +
    geom_line() +
    scale_fill_brewer(guide = "none") +
    theme_bw()



# dummy data with 2 groups
dt2 <- tibble(category = c(rep("A", n), rep("B", n)),
              value = c(rnorm(n)^2, rnorm(n, mean = 2)))

dt2 <- dt2 %>%
    group_by(category) %>% 
    mutate(dy = approxdens(value),    
           p = percent_rank(value),
           pcat = as.factor(cut(p, breaks = probs,
                                include.lowest = TRUE)))

# faceted plot
ggplot(dt2, aes(value, dy)) +
    geom_ribbon(aes(ymin = 0, ymax = dy, fill = pcat)) +
    geom_line() +
    facet_wrap(~ category, nrow = 2, scales = "fixed") +
    scale_fill_brewer(guide = "none") +
    theme_bw()

此内容由reprex包 (v0.2.0)于2018年7月13日创建。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接