【问题标题】:Make violin plot in r when you are already given the percent distribution当你已经得到百分比分布时,在 r 中制作小提琴图
【发布时间】:2020-05-14 20:02:23
【问题描述】:

我被要求制作一个小提琴图,显示四级大学中学生的 ACT 分数分布(大学根据质量衡量标准进行分级。)该图应该有四把小提琴,每个质量层都有一把(即x 轴)。 y 轴将是 ACT 分数。小提琴越宽,该级别学生的 ACT 分数越高。

提供给我的数据已经按每个级别中具有特定 ACT 分数的学生百分比进行了细分。它的结构是这样的(这不是真实数据,只是一个虚构的样本):

structure(list(score = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 
3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 
3, 4, 5, 6, 7, 8, 9, 10), quality_tier = c("Tier 4", "Tier 4", 
"Tier 4", "Tier 4", "Tier 4", "Tier 4", "Tier 4", "Tier 4", "Tier 4", 
"Tier 4", "Tier 3", "Tier 3", "Tier 3", "Tier 3", "Tier 3", "Tier 3", 
"Tier 3", "Tier 3", "Tier 3", "Tier 3", "Tier 2", "Tier 2", "Tier 2", 
"Tier 2", "Tier 2", "Tier 2", "Tier 2", "Tier 2", "Tier 2", "Tier 2", 
"Tier 1", "Tier 1", "Tier 1", "Tier 1", "Tier 1", "Tier 1", "Tier 1", 
"Tier 1", "Tier 1", "Tier 1"), pct_students = c(0.25, 5, 10, 
15, 25, 15, 10, 12, 7, 0.75, 1.5, 6, 8, 12, 34, 17, 10, 6, 4, 
1.5, 5, 5, 13, 18, 5, 22, 13, 9, 5, 5, 0.8, 1, 14, 20, 25, 20, 
9, 8, 2, 0.2)), row.names = c(NA, -40L), class = c("tbl_df", 
"tbl", "data.frame"))

我不知道如何把它变成小提琴情节。网上所有的教程都说使用 ggplot + geom_violin。但是它们都没有包含一个示例,其中您实际上得到了一个值的百分比分布,而不是自己计算百分比分布。我应该如何重组这些数据以便我可以制作小提琴图,或者如果我不能重组数据,我应该要求什么数据?

【问题讨论】:

  • 您能展示一下您尝试过的代码吗?这将有助于更好地理解您的问题。
  • 你知道每个层级的学生人数吗?

标签: r ggplot2


【解决方案1】:
library(ggplot2)
library(dplyr)
library(tidyr)

数据

df <- structure(list(score = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 
3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 
3, 4, 5, 6, 7, 8, 9, 10), quality_tier = c("Tier 4", "Tier 4", 
"Tier 4", "Tier 4", "Tier 4", "Tier 4", "Tier 4", "Tier 4", "Tier 4", 
"Tier 4", "Tier 3", "Tier 3", "Tier 3", "Tier 3", "Tier 3", "Tier 3", 
"Tier 3", "Tier 3", "Tier 3", "Tier 3", "Tier 2", "Tier 2", "Tier 2", 
"Tier 2", "Tier 2", "Tier 2", "Tier 2", "Tier 2", "Tier 2", "Tier 2", 
"Tier 1", "Tier 1", "Tier 1", "Tier 1", "Tier 1", "Tier 1", "Tier 1", 
"Tier 1", "Tier 1", "Tier 1"), pct_students = c(0.25, 5, 10, 
15, 25, 15, 10, 12, 7, 0.75, 1.5, 6, 8, 12, 34, 17, 10, 6, 4, 
1.5, 5, 5, 13, 18, 5, 22, 13, 9, 5, 5, 0.8, 1, 14, 20, 25, 20, 
9, 8, 2, 0.2)), row.names = c(NA, -40L), class = c("tbl_df", 
"tbl", "data.frame"))


数据争吵

geom_violin 想要获得计数数据而不是处理后的百分比数据。不知道每一层的人数,我任意将百分比值乘以 10 得到整数。

tidyr::uncount 就是这样做的,因此您可以执行一个简单的ggplot 可视化。


df1 <- 
  df %>% 
  mutate(nr = pct_students*10) %>% 
  uncount(nr)

情节

  
ggplot(df1, aes(quality_tier, score))+
  geom_violin()

reprex package (v0.3.0) 于 2020-05-14 创建

【讨论】:

  • 给自己更多的信任彼得(这就是为什么我问他有多少学生)。必须约为 10 才能为您提供原始表格中显示的百分比。它也是每个质量等级的得分类别数量,因此远胜于任意
  • 谢谢@ChuckP;但我认为你假设有 10 名学生还是 10,000 名学生并不重要,情节看起来是一样的。我认为如果您使用百分比值,它会起作用。重要的是uncount 数据。我打算看看 geom_violin 是否有stat = "identity" 选项,所以它可以像geom_hist 一样对待。那是另一天。
  • LOL @Peter 这就是我在看到你的答案之前所做的工作,但是剧透警告在你的代码中尝试pct_students*100 并且情节看起来会有所不同,去 1000,它们看起来会非常不同。
  • 嗯@ChuckP 我认为一些家庭作业是为了更好地理解正在绘制的内容。我认为问题在于实际上绘制的是离散数据而不是连续数据。在文档中快速查找:“小提琴图是连续分布的紧凑显示。”所以 geom_violin 可能不是这个数据的正确可视化!嗯,这个需要好好想想……
  • @ChuckP 此链接提供了一个有用的介绍,介绍了使用geom_violin 绘制离散数据的问题:stackoverflow.com/questions/13744979/…geom_violin 包含一个 adjust 参数,它允许“平滑”颠簸。
【解决方案2】:

这是一种非常老式的方法:如果您不能使用 ggplot 的 stat 为您设置小提琴,只需从头开始构建您的小提琴。假设 dat 变量是您的示例数据。

# Split by group
mylist <- split(dat, dat$quality_tier)

# Parameterise as polygons
newdat <- lapply(seq_along(mylist), function(i) {
  dat <- mylist[[i]]
  new <- data.frame(
    x = c(dat$pct_students, -rev(dat$pct_students)),
    y = c(dat$score, rev(dat$score)),
    i = i
  )
  new
})

# Reconstruct
newdat <- do.call(rbind, newdat)
newdat$group <- names(mylist)[newdat$i]

# Set widths of violins
violin_width <- 0.9
newdat$x <- scales::rescale(newdat$x, to = c(-1, 1) * 0.5 * violin_width)

# Plot polygons
ggplot(newdat, aes(x + i, y, fill = group)) +
  geom_polygon() +
  scale_x_continuous(breaks = unique(newdat$i),
                     labels = unique(newdat$group))

我知道这看起来不太好,但如果你的合作者想要更好的情节,他应该提供更好的数据。

【讨论】:

  • 我喜欢这种方法,因为它最忠实于给定的数据。我想如果你真的想要那种外观,你可以使用样条线来平滑多边形。我也想知道丝带会不会比多边形更容易?
【解决方案3】:

另一个 dplyr 解决方案,使用 sample

library(dplyr)
library(ggplot2)

df %>%
  split(df$quality_tier) %>%
  lapply(function(x) {
    tibble(tier = rep(x$quality_tier[1], 1000), 
           score = sample(x$score, 1000, prob = x$pct_students, replace = TRUE))
    }) %>%
  bind_rows() %>%
  ggplot(aes(tier, score, fill = tier)) + 
  geom_violin() +
  coord_flip()

reprex package (v0.3.0) 于 2020-05-14 创建

【讨论】:

    猜你喜欢
    • 2021-06-29
    • 2018-01-15
    • 2011-09-11
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    • 2016-06-19
    • 2022-08-04
    • 2020-11-25
    相关资源
    最近更新 更多