【问题标题】:How to calculate share per category within a column?如何计算列中每个类别的份额?
【发布时间】:2017-03-24 05:13:37
【问题描述】:
df = data.frame(week = as.factor(rep(c(1, 2), times = 5)),
                name = as.factor(rep(LETTERS[1:5], times = 2)),
                count = rpois(n = 10, lambda = 20))

    > df
     week   name count
1       1      A    16
2       2      B    14
3       1      C    23
4       2      D    15
5       1      E    12
6       2      A    15
7       1      B    23
8       2      C    22
9       1      D    22
10      2      E    26

我想计算每个名字每周的计数份额。 起初我打算使用以下方法:

transform(df, week1_share = ifelse(week == "1", round((df$count / sum(df$count)  * 100),2), NA))
transform(df, week2_share = ifelse(week == "2", round((df$count / sum(df$count)  * 100),2), NA))

但是随后将每一列合并,最终将其作为条形图上的标签,似乎效率太低了。必须有某种我还不知道的快速解决方案。

基本上我想做的事情如下,但添加上面可能计算的份额百分比以匹配每个框。

ggplot(df, aes(reorder(week, -count),count, color = "white", group = name, fill = name))+
        geom_bar(position = "stack", stat = "identity") +
        scale_y_continuous(labels=comma)+
        ggthemes::scale_color_tableau()

我不知道为什么重新排序功能经常在我身上失败。如果您有任何以 desc 排序顺序的提示,请分享。

【问题讨论】:

  • 你的意思是aggregate(count ~ name, df, function(i)round(i*100/sum(i), 2))?或df$new <- with(df, ave(count, name, FUN = function(i)(round(i*100/sum(i), 2))))
  • 对于每周的计数份额,您可以使用 dplyr 按周分组并变异以添加列。 library(dplyr)df<- mutate(group_by(df,week), round(count/sum(count) * 100, 2))
  • 嗨,好问题,你能改正你的错字吗:data_frame 而不是 data.frame,供人们复制粘贴数据。

标签: r ggplot2 bar-chart geom-bar


【解决方案1】:

您提供的数据已被使用:

# Loading the required data
df = data.frame(week = as.factor(rep(c(1, 2), times = 5)),
                name = as.factor(rep(LETTERS[1:5], times = 2)),
                count = rpois(n = 10, lambda = 20))

使用plyr包函数,计算出标签的百分比和相对位置。

#Loading the required packages    
library(plyr)
library(ggplot2)

# Calculating the percentages
df = ddply(df, .(week), transform, percent = round(count/sum(count) * 100))

# Calculating the position for plotting
df = ddply(df, .(week), transform, pos = cumsum(percent) - (0.5 * percent))

使用上面计算的信息,绘图已经完成。

# Basic graph
p10 <- ggplot() + geom_bar(aes(y = percent, x = week, fill = name), 
                       data = df, stat="identity")

# Adding data labels
p10 <- p10 + geom_text(data=df, aes(x = week, y = pos, 
                                label = paste0(percent,"%")), size=4)
p10

这是你一直在寻找的吗?

【讨论】:

  • 这正是我想要的。太感谢了!我学到了新东西!
  • 我还有一个额外的问题。 “#计算绘图位置”这是将标签放在框中间的方法吗?这是如何运作的?你能给我一些阅读参考吗?
  • 用于计算每组内的累计和,这里week。你可以得到cumsum的用法,在ggplot绘图上下文中使用cumsum12
  • 出于某种原因,在我的情况下,除了一个更改外,相同的代码有效 - 我使用:y = 100-pos 而不是 y = pos。否则我的百分比标签是从下到上放置的,而图表上的条形图是从上到下的顺序放置。
【解决方案2】:

使用splitunsplitprop.table 在基础 R 中的解决方案是:

df2 <- unsplit(lapply(split(df, df$week), 
                  function(x){
                    x$prop <- prop.table(x$count)
                    x}
                  ), df$week)

简而言之,split 根据第二个参数返回一个 data.frames 拆分列表,unsplit 将拆分生成的列表放回到一起。

使用data.table 包会更短:

library(data.table)
dt <- data.table(df)
dt[, prop := prop.table(count), by=week]

我对 dplyr 不是很流利,但我确信还有一个非常简短直接的解决方案。

编辑:这是我在 dplyr/magrittr 中提出的:

library(dplyr)
df3 <- df %>%
   group_by(week) %>%
   mutate(freq = prop.table(count))

【讨论】:

  • 我也更喜欢使用 data.table 来 dplyr。感谢您分享您的知识!
猜你喜欢
  • 1970-01-01
  • 2011-10-16
  • 2019-05-19
  • 1970-01-01
  • 2021-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-06
相关资源
最近更新 更多