【问题标题】:In R how can I make a six-bar chart where each bar contains a range of data?在 R 中,如何制作一个六条形图,其中每个条形包含一系列数据?
【发布时间】:2020-02-25 19:38:32
【问题描述】:

我有一个电子表格,其中显示了棒球运动员的年龄和所参加的比赛。

structure(list(Player = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 
12, 13, 14, 15, 16, 17, 18), Games = c(21, 7, 159, 156, 10, 152, 
23, 68, 13, 123, 29, 13, 111, 2, 84, 15, 140, 93), Age = c(34, 
23, 33, 22, 28, 24, 28, 33, 33, 29, 29, 25, 20, 41, 37, 21, 22, 
31), under21 = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 
0, 0, 0), Y21to25 = c(0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 
0, 0, 1, 1, 0), Y26to30 = c(0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 
0, 0, 0, 0, 0, 0, 0), Y31to35 = c(1, 0, 1, 0, 0, 0, 0, 1, 1, 
0, 0, 0, 0, 0, 0, 0, 0, 1), Y36to40 = c(0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0), over40 = c(0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0)), row.names = c(NA, 18L), class = "data.frame")

这是使用 glimpse(df) 的另一个视图。出于说明目的,我添加了从“under21”到“over40”的六列。

Observations: 18
Variables: 9
$ Player  <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18
$ Games   <dbl> 21, 7, 159, 156, 10, 152, 23, 68, 13, 123, 29, 13, 111, 2, 84…
$ Age     <dbl> 34, 23, 33, 22, 28, 24, 28, 33, 33, 29, 29, 25, 20, 41, 37, 2…
$ under21 <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0
$ Y21to25 <dbl> 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0
$ Y26to30 <dbl> 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0
$ Y31to35 <dbl> 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1
$ Y36to40 <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0
$ over40  <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0

我需要的是一个条形图,其中有六个条形图(“under21”到“over40”)从 x 轴上升。 y 轴“游戏”将显示每个年龄组中所有玩家玩的游戏数量。因此,“under21”栏将显示所有 21 岁以下玩家的总游戏数,依此类推。

最好的方法是什么?

【问题讨论】:

  • 玩家13under21Y36to40 组中都有一个值1

标签: r ggplot2


【解决方案1】:

您可以使用tidyr 包(tidyverse 的一部分)中的pivot_longer 函数将数据框重新整形为更长的格式,过滤掉 0 个值,然后使用 @ 绘制它们所属类别的函数中的游戏总数987654326@:

library(tidyverse)
df %>% pivot_longer(-c(Player, Games, Age), names_to = "var", values_to = "val") %>%
  mutate(var = factor(var, levels = c("under21","Y21to25","Y26to30","Y31to35","Y36to40","over40"))) 
  
# A tibble: 108 x 5
   Player Games   Age var       val
    <dbl> <dbl> <dbl> <fct>   <dbl>
 1      1    21    34 under21     0
 2      1    21    34 Y21to25     0
 3      1    21    34 Y26to30     0
 4      1    21    34 Y31to35     1
 5      1    21    34 Y36to40     0
 6      1    21    34 over40      0
 7      2     7    23 under21     0
 8      2     7    23 Y21to25     1
 9      2     7    23 Y26to30     0
10      2     7    23 Y31to35     0
# … with 98 more rows
library(tidyverse)
df %>% pivot_longer(-c(Player, Games, Age), names_to = "var", values_to = "val") %>%
  mutate(var = factor(var, levels = c("under21","Y21to25","Y26to30","Y31to35","Y36to40","over40"))) %>%
  filter(val != 0) %>%
  ggplot(aes(x = var, y = Games, fill = var))+
  geom_col()

看起来是你想要达到的目标吗?


编辑:计算ggplot2之外的游戏总和

您可以自己计算每个类别的游戏总数:

library(dplyr)
library(tidyr)
df %>% pivot_longer(-c(Player, Games, Age), names_to = "var", values_to = "val") %>%
  mutate(var = factor(var, levels = c("under21","Y21to25","Y26to30","Y31to35","Y36to40","over40"))) %>%
  filter(val != 0) %>%
  group_by(var) %>% 
  summarise(Games = sum(Games)) 

# A tibble: 6 x 2
  var     Games
  <fct>   <dbl>
1 under21   111
2 Y21to25   483
3 Y26to30   185
4 Y31to35   354
5 Y36to40   195
6 over40      2

您可以添加管道序列以直接绘制它:

library(dplyr)
library(tidyr)
library(gpglot2)
df %>% pivot_longer(-c(Player, Games, Age), names_to = "var", values_to = "val") %>%
  mutate(var = factor(var, levels = c("under21","Y21to25","Y26to30","Y31to35","Y36to40","over40"))) %>%
  filter(val != 0) %>%
  group_by(var) %>% 
  summarise(Games = sum(Games)) %>%
  ggplot(aes(x = var, y = Games, fill = var))+
  geom_col()

你会得到完全相同的情节

【讨论】:

  • “var”对象是否包含“under21”到“over40”的列名及其数据(零和一)? (“names_to”是否同时传输?)鉴于“fill = var”,条形图如何显示游戏数据总和?
  • 我编辑了我的答案,以便在绘图之前向您展示数据框的外观。 Var 包含您将使用 x 轴的类别名称。正如我们输入y = Gamesgeom_col 将在x 的函数中求和y,所以这里是类别函数中的Games 的总和。 fill = var 只是为栏添加一些颜色。有意义吗?
  • 感谢您的编辑。我确信“所以在这里,游戏在类别功能中的总和”的含义。
  • 自己计算每个类别的Games总和,你会看到它是ggplot2显示的数字。基本上,对于每个类别,它都是游戏的总和。
  • 我编辑了我的答案,向您展示了另一种方法,您可以计算 ggplot2 之外的每个类别的游戏总数。你得到完全相同的情节。现在更有意义了吗?
【解决方案2】:

编辑 -- reshape2 已被 tidyr 取代。请参阅dc37's answer 了解更新的方法。


此解决方案使用reshape2 包中的melt 将年龄变量折叠成两列:variablevalue。从那里,您可以对数据框进行子集化以仅包含 value1 的行,然后创建条形图,指定 stat = "identity" 以让 geom_bar 知道您是 supplying your own y value

library(reshape2)
library(ggplot2)

stats <- structure(list(Player = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 
12, 13, 14, 15, 16, 17, 18), Games = c(21, 7, 159, 156, 10, 152, 
23, 68, 13, 123, 29, 13, 111, 2, 84, 15, 140, 93), Age = c(34, 
23, 33, 22, 28, 24, 28, 33, 33, 29, 29, 25, 20, 41, 37, 21, 22, 
31), under21 = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 
0, 0, 0), Y21to25 = c(0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 
0, 0, 1, 1, 0), Y26to30 = c(0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 
0, 0, 0, 0, 0, 0, 0), Y31to35 = c(1, 0, 1, 0, 0, 0, 0, 1, 1, 
0, 0, 0, 0, 0, 0, 0, 0, 1), Y36to40 = c(0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0), over40 = c(0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0)), row.names = c(NA, 18L), class = "data.frame")

stats <- melt(stats, id.vars = c("Player","Games","Age"))
stats <- stats[stats$value == 1,]

p <-  ggplot(stats, aes(x = variable, y = Games))
p + geom_bar(stat = "identity") + xlab("")

此代码不考虑同时出现在under21Y36to40 组中的玩家13

【讨论】:

  • 顺便说一句,geom_bar(stat = "identity") 实际上与geom_col() 相同,因为geom_col 默认使用stat = "identity"ggplot2.tidyverse.org/reference/geom_bar.html。但两者都是正确的。
  • @Dirigible,我发现有趣的是 Games 是 id.vars 之一,而不是度量变量。为什么会这样?另外,感谢您发现玩家 13 分为两组。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-21
  • 2019-02-15
  • 2020-09-22
  • 2020-09-18
相关资源
最近更新 更多