【问题标题】:R ggplot2 histogram overlays with normalized values for each histogramR ggplot2 直方图覆盖每个直方图的归一化值
【发布时间】:2018-08-02 00:49:44
【问题描述】:

我想创建一个比较三组的直方图。但是,我想通过每组内的计数总数而不是计数总数来标准化每个直方图。这是我的代码。

library(ggplot2)
library(reshape2)
# Creates dataset
set.seed(9)
df<- data.frame(values = c(runif(400,20,50),runif(300,40,80),runif(600,0,30)),labels = c(rep("med",400),rep("high",300),rep("low",600)))

levs <- c("low", "med", "high")
df$labels <- factor(df$labels, levels = levs)

ggplot(df, aes(x=values, fill=labels)) + 
    geom_histogram(aes(y=..density..), 
                   breaks= seq(0, 80, by = 2),
                   alpha=0.2, 
                   position="identity")

这会生成一个似乎按密度归一化的直方图。

但是,我决定对照我对该密度的手动验证来交叉检查该密度图。为此,我使用了以下代码:

# Separates the low medium and high groups
df1 <- df[df$labels == "low",]
df2 <- df[df$labels == "med",]
df3 <- df[df$labels == "high",]

# creates histogram for each group that is normalized by the total number of counts
hist_temp <- hist(df1$values, breaks=seq(0,80, by=2))
    tdf <- data.frame(hist_temp$breaks[2:length(hist_temp$breaks)],hist_temp$counts)
    colnames(tdf) <- c("bins","counts")
    tdf$norm <- tdf$counts/(sum(tdf$counts))
        low1 <- tdf

hist_temp <- hist(df2$values, breaks=seq(0,80, by=2))
    tdf <- data.frame(hist_temp$breaks[2:length(hist_temp$breaks)],hist_temp$counts)
    colnames(tdf) <- c("bins","counts")
    tdf$norm <- tdf$counts/(sum(tdf$counts))
        med1 <- tdf

hist_temp <- hist(df3$values, breaks=seq(0,80, by=2))
    tdf <- data.frame(hist_temp$breaks[2:length(hist_temp$breaks)],hist_temp$counts)
    colnames(tdf) <- c("bins","counts")
    tdf$norm <- tdf$counts/(sum(tdf$counts))
        high1 <- tdf

# Combines normalized histograms for each data frame and melts them into a single vector for plotting
Tdata <- data.frame(low1$bins,low1$norm,med1$norm,high1$norm)
    colnames(Tdata) <- c("bin","low", "med", "high")
    Tdata<- melt(Tdata,id = "bin")

levs <- c("low", "med", "high")
Tdata$variable <- factor(Tdata$variable, levels = levs)

# Plot the data
ggplot(Tdata, aes(group=variable, colour= variable)) + 
    geom_line(aes(x = bin, y = value))

这会产生:

正如你所看到的,它们彼此完全不同,我不知道为什么。两者的 Y 轴应该相同,但事实并非如此。所以,假设我没有犯一些愚蠢的数学错误,我相信我希望直方图看起来像线图,但我想不出一种方法来实现这一点。感谢您提供任何帮助,并提前感谢您。


已编辑以添加更多无效示例:

我也尝试过在这段代码中使用 ..count../(sum(..count..)) 方法:

# Histogram where each histogram is divided by the total count of all groups    
    ggplot(df, aes(x=values, fill=labels, group=labels)) + 
        geom_histogram(aes(y=(..count../sum(..count..))), 
                       breaks= seq(0, 80, by = 2),
                       alpha=0.2, 
                       position="identity")

这些结果:

这只是标准化为所有直方图的总数。这也不能反映我在折线图中看到的内容。此外,我尝试用 ..ncount.. 代替 ..count..(在分子、分母以及分子和分母中),这也不会重新创建折线图中显示的结果。

此外,我尝试使用“position=stack”而不是使用以下代码的身份:

    ggplot(df, aes(x=values, fill=labels, group=labels)) + 
        geom_histogram(aes(y=..density..), 
                       breaks= seq(0, 80, by = 2),
                       alpha=0.2, 
                       position="stack")

得到了这个结果:

这也不反映折线图中显示的值。


取得了进展!使用this post by Joran 中概述的方法,我现在可以生成与折线图相同的直方图。下面是代码:

# Plot where each histogram is normalized by its own counts.  
ggplot(df,aes(x=values, fill=labels, group=labels)) + 
    geom_histogram(data=subset(df, labels == 'high'),
                   aes(y=(..count../sum(..count..))), 
                   breaks= seq(0, 80, by = 2),
                   alpha = 0.2) + 
    geom_histogram(data=subset(df, labels == 'med'),
                   aes(y=(..count../sum(..count..))), 
                   breaks= seq(0, 80, by = 2),
                   alpha = 0.2) +
    geom_histogram(data=subset(df, labels == 'low'),
                   aes(y=(..count../sum(..count..))), 
                   breaks= seq(0, 80, by = 2),
                   alpha = 0.2) +
    scale_fill_manual(values = c("blue","red","green"))

生成此图:

但是,我仍然无法重新排序数据,以便图例读取“低”然后是“中”然后是“高”,而不是按字母顺序排列。我已经设定了因素的水平。 (见第一块代码)。有什么想法吗?

【问题讨论】:

  • 在第一个块中,您使用了 y = ..density..,我猜这是概率密度的原因。尝试添加 group = 标签并使用 y = ..count../sum(..count..) 代替。
  • 感谢您的回复。不幸的是,这似乎并没有创建我正在寻找的线图。我在上面的行之后添加了结果以显示产生的结果。基本上, ..count../sum(..count..) 似乎只有在您有一个直方图时才有效。当你有倍数时,总和(..count..)除以所有直方图的总和,得到的分数太低了。
  • 如果是这种情况,我有一个缺乏优雅但可以工作的解决方案。按标签过滤数据框并使用 3 层而不是 1 层。
  • @VitorBianchiLanzetta 感谢您的评论。这似乎确实有效。如果可能的话,我仍然想要一些更……优雅的东西。剧情看起来并不太奇怪。也许我会花时间编辑 ggplot2 源并将其提交给开发人员以供他们包含。
  • 我有一种感觉,也许foreach 是要走的路,但我现在没有时间解决它。你应该试试看:D

标签: r ggplot2 histogram normalize


【解决方案1】:

要对每个类别使用计数,可能是position="stack"

ggplot(df, aes(x=values, fill=labels)) + 
  geom_histogram(aes(y=..density..), 
                 breaks= seq(0, 80, by = 2),
                 alpha=0.4, 
                 position="stack") +
  geom_density(alpha=.2, position="stack")

它给了我这个distribution,但看起来仍然与你的第二个情节不同。

【讨论】:

  • 感谢您的回复。我已将代码作为另一种似乎不起作用的方法添加到我的帖子中。在上面睡觉并再次查看线图代码后,我仍然看不到我可能做错了什么。我可以生成六种不同的直方图也很疯狂,它们都以不同的方式归一化,但它们都不是对我最有意义的方式。
猜你喜欢
  • 2014-12-31
  • 2011-10-20
  • 1970-01-01
  • 2021-09-06
  • 2013-06-20
  • 2015-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多