ggplot2 循环数据的密度
ggplot2 density of circular data
我有一个数据集,其中 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.
中所示的极坐标图
要消除边缘效应,您可以堆叠三个数据副本,创建密度估计,然后仅显示中间数据副本的密度。这将保证 "wrap around" 密度函数从一条边到另一条边的连续性。
下面是一个将您的原始情节与新版本进行比较的示例。我使用 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:
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")
我有一个数据集,其中 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.
要消除边缘效应,您可以堆叠三个数据副本,创建密度估计,然后仅显示中间数据副本的密度。这将保证 "wrap around" 密度函数从一条边到另一条边的连续性。
下面是一个将您的原始情节与新版本进行比较的示例。我使用 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:
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")