r:ecdf over histogram

时间:2015-03-26 21:18:12

标签: r plot histogram cdf

在R中

ecdf我可以绘制经验累积分布函数

plot(ecdf(mydata))

hist我可以绘制数据的直方图

hist(mydata)

如何在同一图中绘制直方图和ecdf?

修改

我尝试制作类似的东西

https://mathematica.stackexchange.com/questions/18723/how-do-i-overlay-a-histogram-with-a-plot-of-cdf

6 个答案:

答案 0 :(得分:7)

也有点晚了,这是另一个用第二个y轴扩展@Christoph解决方案的解决方案。

par(mar = c(5,5,2,5))
set.seed(15)
dt <- rnorm(500, 50, 10)
h <- hist(
  dt,
  breaks = seq(0, 100, 1),
  xlim = c(0,100))

par(new = T)

ec <- ecdf(dt)
plot(x = h$mids, y=ec(h$mids)*max(h$counts), col = rgb(0,0,0,alpha=0), axes=F, xlab=NA, ylab=NA)
lines(x = h$mids, y=ec(h$mids)*max(h$counts), col ='red')
axis(4, at=seq(from = 0, to = max(h$counts), length.out = 11), labels=seq(0, 1, 0.1), col = 'red', col.axis = 'red')
mtext(side = 4, line = 3, 'Cumulative Density', col = 'red')

Histogram with CDF, two scales and two y-axes

诀窍如下:你没有在你的情节中添加一条线,而是在顶部绘制另一个情节,这就是我们需要par(new = T)的原因。然后你必须稍后添加y轴(否则它将在左边的y轴上绘制)。

致谢here(@tim_yates答案)和there

答案 1 :(得分:4)

有两种方法可以解决这个问题。一种是忽略不同的比例并在直方图中使用相对频率。这导致更难以阅读直方图。第二种方法是改变一个或另一个元素的规模。

我怀疑this question很快会对你感兴趣,特别是@hadley的答案。

ggplot2单一刻度

以下是ggplot2中的解决方案。我不确定你会对结果感到满意,因为CDF和直方图(计数或相对)的视觉尺度完全不同。请注意,此解决方案将数据放在名为mydata的数据框中,并在x中包含所需的变量。

library(ggplot2)
set.seed(27272)
mydata <- data.frame(x=  rexp(333, rate=4) + rnorm(333))

 ggplot(mydata, aes(x)) + 
     stat_ecdf(color="red") + 
     geom_bar(aes(y = (..count..)/sum(..count..))) 

ggplotecdfhist

基础R多尺度

在这里,我将重新调整经验CDF,使其不是最大值1,而是最大值是具有最高相对频率的bin。

h  <- hist(mydata$x, freq=F)
ec <- ecdf(mydata$x)
lines(x = knots(ec), 
    y=(1:length(mydata$x))/length(mydata$x) * max(h$density), 
    col ='red')

baseRecdfhist

答案 2 :(得分:3)

您可以尝试使用第二轴的ggplot方法

set.seed(15)
a <- rnorm(500, 50, 10)

# calculate ecdf with binsize 30
binsize=30
df <- tibble(x=seq(min(a), max(a), diff(range(a))/binsize)) %>% 
        bind_cols(Ecdf=with(.,ecdf(a)(x))) %>% 
        mutate(Ecdf_scaled=Ecdf*max(a))
# plot
ggplot() + 
  geom_histogram(aes(a), bins = binsize) +
  geom_line(data = df, aes(x=x, y=Ecdf_scaled), color=2, size = 2) + 
  scale_y_continuous(name = "Density",sec.axis = sec_axis(trans = ~./max(a), name = "Ecdf"))

enter image description here

答案 3 :(得分:2)

正如已经指出的那样,这是有问题的,因为您要合并的图具有不同的y尺度。你可以尝试

set.seed(15)
mydata<-runif(50)
hist(mydata, freq=F)
lines(ecdf(mydata))

获取

enter image description here

答案 4 :(得分:1)

虽然有点迟了......另一个使用预设箱的版本:

set.seed(15)
dt <- rnorm(500, 50, 10)
h <- hist(
    dt,
    breaks = seq(0, 100, 1),
    xlim = c(0,100))
    ec <- ecdf(dt)
    lines(x = h$mids, y=ec(h$mids)*max(h$counts), col ='red')
    lines(x = c(0,100), y=c(1,1)*max(h$counts), col ='red', lty = 3) # indicates 100%
    lines(x = c(which.min(abs(ec(h$mids) - 0.9)), which.min(abs(ec(h$mids) - 0.9))), # indicates where 90% is reached
          y = c(0, max(h$counts)), col ='black', lty = 3)

enter image description here

(只有第二个y轴还没有工作......)

答案 5 :(得分:0)

除了先前的答案外,我还想让ggplot进行乏味的计算(与@Roman's solution相比,后者应我的要求进行了足够的更新),即计算并绘制直方图和< / strong>计算并覆盖ECDF。我想出了以下(伪代码):

# 1. Prepare the plot
plot <- ggplot() + geom_hist(...)

# 2. Get the max value of Y axis as calculated in the previous step
maxPlotY <- max(ggplot_build(plot)$data[[1]]$y)

# 3. Overlay scaled ECDF and add secondary axis
plot +
  stat_ecdf(aes(y=..y..*maxPlotY)) +
  scale_y_continuous(name = "Density", sec.axis = sec_axis(trans = ~./maxPlotY, name = "ECDF"))

这样,您无需预先计算所有内容并将结果提供给ggpplot。躺下,让它为您做所有事情!