ggplot2循环数据密度

时间:2016-03-28 16:24:14

标签: r ggplot2 statistics kernel-density

我有一个数据集,其中x代表一年中的某一天(比如生日),我想创建一个密度图。 此外,由于我有一些分组信息(比如男孩或女孩),我想使用ggplot2的功能来制作密度图。

起初很容易:

require(ggplot2); require(dplyr)
bdays <- data.frame(gender = sample(c('M', 'F'), 100, replace = T), bday = sample(1:365, 100, replace = T))
bdays %>% ggplot(aes(x = bday)) + geom_density(aes(color = factor(gender)))

然而,由于边缘效应,这给出了很差的估计。 我想应用这样一个事实:我可以使用圆形坐标,使得365 + 1 = 1 - 12月31日之后的一天是1月1日。 我知道circular包提供了此功能,但我没有使用stat_function()调用实现它的任何成功。 使用ggplot2对我来说特别有用,因为我希望能够使用构面,aes调用等。

此外,为了澄清,我希望看起来像geom_density - 我不是在寻找像Circular density plot using ggplot2所示的极地情节。

1 个答案:

答案 0 :(得分:7)

要删除边缘效果,您可以堆叠三个数据副本,创建密度估计值,然后仅显示中间数据副本的密度。这将保证密度函数从一个边缘到另一个边缘的“环绕”连续性。

以下是将原始图表与新版本进行比较的示例。我已经使用adjust参数在两个图之间设置相同的带宽。另请注意,在圆形版本中,如果要将它们添加到1,则需要重新规范化密度:

set.seed(105)
bdays <- data.frame(gender = sample(c('M', 'F'), 100, replace = T), bday = sample(1:365, 100, replace = T))

# Stack three copies of the data, with adjusted values of bday
bdays = bind_rows(bdays, bdays, bdays)
bdays$bday = bdays$bday + rep(c(0,365,365*2),each=100)

# Function to adjust bandwidth of density plot
# Source: http://stackoverflow.com/a/24986121/496488
bw = function(b,x) b/bw.nrd0(x)

# New "circularized" version of plot
bdays %>% ggplot(aes(x = bday)) + 
  geom_density(aes(color = factor(gender)), adjust=bw(10, bdays$bday[1:100])) +
  coord_cartesian(xlim=c(365, 365+365+1), expand=0) +
  scale_x_continuous(breaks=seq(366+89, 366+365, 90), labels=seq(366+89, 366+365, 90)-365) +
  scale_y_continuous(limits=c(0,0.0016))
  ggtitle("Circularized")

# Original plot
ggplot(bdays[1:100,], aes(x = bday)) + 
  geom_density(aes(color = factor(gender)), adjust=bw(30, bdays$bday[1:100])) +
  scale_x_continuous(breaks=seq(90,360,90), expand=c(0,0)) +
  ggtitle("Not Circularized")

enter image description here