r: ecdf по гистограмме

в 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


person JuanPablo    schedule 26.03.2015    source источник
comment
Обязательно ознакомьтесь с вопросом и ответом, на который я ссылаюсь, почему этот вид визуализации не поддерживается в ggplot2. Тем не менее, это возможно в базе R. Но определенно потребуется больше, чем однострочный.   -  person vpipkt    schedule 27.03.2015


Ответы (6)


Также немного поздно, вот еще одно решение, которое расширяет @Christoph's Solution второй осью y.

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')

Гистограмма с CDF, двумя шкалами и двумя осями Y

Уловка заключается в следующем: вы не добавляете линию к своему сюжету, а строите сверху другой сюжет, поэтому нам нужно par(new = T). Затем вам нужно будет добавить ось Y позже (иначе она будет нанесена на ось Y слева).

Кредиты находятся здесь (ответ @tim_yates) и здесь.

person symbolrush    schedule 18.10.2016

Есть два способа сделать это. Один из них - игнорировать различные масштабы и использовать относительную частоту в вашей гистограмме. Это затрудняет чтение гистограммы. Второй способ - изменить масштаб того или иного элемента.

Я подозреваю, что этот вопрос скоро станет вам интересен, особенно ответ @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 его максимальное значение было любым бином, имеющим наивысшую относительную частоту.

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

person vpipkt    schedule 26.03.2015

вы можете попробовать подход 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"))

введите описание изображения здесь

Редактировать

Поскольку масштабирование было неправильным, я добавил второе решение, рассчитав все заранее:

binsize=30
a_range= floor(range(a)) +c(0,1)

b <- seq(a_range[1], a_range[2], round(diff(a_range)/binsize)) %>% floor() 


df_hist <- tibble(a) %>% 
  mutate(gr = cut(a,b, labels = floor(b[-1]), include.lowest = T, right = T)) %>% 
  count(gr) %>% 
  mutate(gr = as.character(gr) %>% as.numeric()) 

# calculate ecdf with binsize 30
df <- tibble(x=b) %>% 
  bind_cols(Ecdf=with(.,ecdf(a)(x))) %>% 
  mutate(Ecdf_scaled=Ecdf*max(df_hist$n))
  
ggplot(df_hist, aes(gr, n)) + 
   geom_col(width = 2, color = "white") + 
   geom_line(data = df, aes(x=x, y=Ecdf*max(df_hist$n)), color=2, size = 2) +
   scale_y_continuous(name = "Density",sec.axis = sec_axis(trans = ~./max(df_hist$n), name = "Ecdf"))

введите описание изображения здесь

person Roman    schedule 09.05.2018
comment
Нормализация строки ECDF некорректна (я тоже не знаю, как это сделать лучше). Лучше выполнить нормализацию относительно самого высокого столбца гистограммы. - person Yan Foto; 12.11.2020
comment
спасибо за быстрый ответ и обновление. Тем временем я придумал собственный ответ, который вы, возможно, захотите проверить (я не профессионал в R!). - person Yan Foto; 14.11.2020

Как уже указывалось, это проблематично, потому что графики, которые вы хотите объединить, имеют такие разные шкалы y. Можешь попробовать

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

получить

введите описание изображения здесь

person MrFlick    schedule 26.03.2015

Хотя немного поздно ... Еще одна версия, работающая с предустановленными лотками:

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)

введите описание изображения здесь

(Только вторая ось Y пока не работает ...)

person Christoph    schedule 12.10.2016

В дополнение к предыдущим ответам я хотел, чтобы ggplot выполнял утомительный расчет (в отличие от решения @Roman, которое было достаточно любезно обновлено по моему запросу), т. е. вычислить и нарисовать гистограмму и вычислить и наложить 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. Просто лягте и позвольте ему сделать все за вас!

person Yan Foto    schedule 14.11.2020