在R ggplot2中,包括stat_ecdf()端点(0,0)和(1,1)

时间:2015-02-19 14:59:03

标签: r ggplot2 ecdf

我正在尝试使用stat_ecdf()来绘制累积成功,作为预测模型创建的排名得分的函数。

#libraries
require(ggplot2)
require(scales)

# fake data for reproducibility
set.seed(123)
n <- 200
df <- data.frame(model_score= rexp(n=n,rate=1:n),
                 obs_set= sample(c("training","validation"),n,replace=TRUE))
df$model_rank <- rank(df$model_score)/n
df$target_outcome <- rbinom(n,1,1-df$model_rank)

# Plot Gain Chart using stat_ecdf()
ggplot(subset(df,target_outcome==1),aes(x = model_rank)) + 
  stat_ecdf(aes(colour = obs_set), size=1) + 
  scale_x_continuous(limits=c(0,1), labels=percent,breaks=seq(0,1,.1)) +
  xlab("Model Percentile") + ylab("Percent of Target Outcome") +
  scale_y_continuous(limits=c(0,1), labels=percent) +
  geom_segment(aes(x=0,y=0,xend=1,yend=1), 
               colour = "gray", linetype="longdash", size=1) +
  ggtitle("Gain Chart")

enter image description here

我想做的就是强制ECDF从(0,0)开始,到(1,1)结束,这样曲线的开头或结尾就没有间隙了。如果可能的话,我想在ggplot2的语法中做到这一点,但我会满足于一个聪明的解决方法。

@Henrik这不是this question的副本,因为我已经使用scale_x__y_continuous()定义了我的限制,并且添加expand_limits()没有做任何事情。它不是PLOT的起源,而是需要修复的stat_ecdf()的端点。

1 个答案:

答案 0 :(得分:1)

不幸的是,stat_ecdf的定义在这里没有任何摆动空间;它在内部确定端点。

有一个先进的解决方案。使用最新版本的ggplot2(devtools::install_github("hadley/ggplot2")),可扩展性得到改善,可以覆盖此行为,但不能没有一些样板。

stat_ecdf2 <- function(mapping = NULL, data = NULL, geom = "step",
                      position = "identity", n = NULL, show.legend = NA,
                      inherit.aes = TRUE, minval=NULL, maxval=NULL,...) {
  layer(
    data = data,
    mapping = mapping,
    stat = StatEcdf2,
    geom = geom,
    position = position,
    show.legend = show.legend,
    inherit.aes = inherit.aes,
    stat_params = list(n = n, minval=minval,maxval=maxval),
    params = list(...)
  )
}


StatEcdf2 <- ggproto("StatEcdf2", StatEcdf,
  calculate = function(data, scales, n = NULL, minval=NULL, maxval=NULL, ...) {
    df <- StatEcdf$calculate(data, scales, n, ...)
    if (!is.null(minval)) { df$x[1] <- minval }
    if (!is.null(maxval)) { df$x[length(df$x)] <- maxval }
    df
  }
)

现在,stat_ecdf2的行为与stat_ecdf相同,但带有可选的minvalmaxval参数。所以这将解决问题:

ggplot(subset(df,target_outcome==1),aes(x = model_rank)) +
  stat_ecdf2(aes(colour = obs_set), size=1, minval=0, maxval=1) +
  scale_x_continuous(limits=c(0,1), labels=percent,breaks=seq(0,1,.1)) +
  xlab("Model Percentile") + ylab("Percent of Target Outcome") +
  scale_y_continuous(limits=c(0,1), labels=percent) +
  geom_segment(aes(x=0,y=0,xend=1,yend=1),
               colour = "gray", linetype="longdash", size=1) +
  ggtitle("Gain Chart")

这里的一个重要警告是,我不知道将来是否会支持当前的可扩展性模型;它在过去曾多次改变,使用“ggproto”的变化是最近的 - 就像2015年7月15日最近一样。

作为一个加号,这让我有机会真正深入了解ggplot的内部结构,这是我一段时间以来所要做的事情。