使用 ggplot2 在 R 中绘制 Google 表单复选框网格响应

Plotting Google Forms checkbox grid responses in R using ggplot2

有人向我发送了 Google Forms 问卷的 CSV 输出,并要求我在 R 中创建摘要图。但是,在分析来自linked 图片中的复选框网格:https://i.stack.imgur.com/0QXZb.png

每个参与者都被要求指定他们所有 children 的年龄。 Child 数字显示在网格顶部(例如 'Child 1'、'Child 2' 等),年龄段显示在 left-hand 侧下方的一列中(例如 10-13、 14-18 等)。可以从网格中选择多个响应,这让我很头疼。

对于 CSV 输出,问题的结果已经分开,因此它们出现在多个列中。年龄段显示为单独的列,一个单元格内可以出现多个响应(参见下面的一个非常小的示例)。真实数据集包含数百名参与者,结果已根据多个标准进行子集化。

x10a.6.9          x10a.10.13        x10a.14.18        x10a.19.23 
child 2;child 3                     child 1
                  child 1
child 3;child 4   child 2                             child 1
                  child 1; child 2     

编辑:丑陋的可复制版本 table(感谢 link Mojoesque):

structure(list(x10a.6.9 = c("child 2;child 3", NA, "child 3;child 4", 
NA), x10a.10.13 = c(NA, "child 1", "child 2", "child 1;child 2"
), x10a.14.18 = c("child 1", NA, NA, NA), x10a.19.23 = c(NA, 
NA, "child 1", NA)), row.names = c(NA, -4L), class = "data.frame")

我想知道我将如何重塑这些数据,以便它可以在简单的条形图中呈现。我不知道如何安排这些数据以使其与 ggplot2 合作。如果可能的话,我希望它看起来像 summary image produced in Google Forms。就目前而言,我不知道如何使用这样的数据沿着 x-axis 绘制年龄并沿着 y-axis 计数。我想在附图中为每个 child 号码分别显示,但不知道从哪里开始。

我们将不胜感激任何帮助。如果问题措辞不当,我深表歉意,也为我难以置信的天真道歉。

编辑:分辨率

我试了一下这个,想出了如何绘制我想要的东西。我将 post 下面使用的步骤,以防它们对其他人有用。

在下面的代码中,data_to_split 对应于上面显示的 table 的小片段。

library(tidyr)
library(dplyr)
library(ggplot2)
data_split <- data_to_split %>% separate_rows(x10a.6.9:x10a.19.23, sep = ";") %>% 
   select(x10a.6.9:x10a.19.23) %>% na_if(., "") %>%
   mutate_all(funs(as.factor))

有必要使用 tidyr 的 separate_rows 函数,因为一个单元格内可能会出现多个响应(例如,一个单元格可以读取 'child 1;child 2')分隔符“;”用于将这些单元格分成多行。

na_if 用于将作为因子读取的空格转换为 NA 值。

在下面的代码中,添加了新列。这些列只是为已读入 R 的列提供了新名称。旧名称很难看且更难使用。

data_split$`6-9` <- data_split$x10a.6.9
data_split$`10-13` <- data_split$x10a.10.13
data_split$`14-18` <- data_split$x10a.14.18
data_split$`19-23` <- data_split$x10a.19.23

在下面的前两行代码中,选择了所有包含年龄段的相关列。然后将数据从宽格式转换为长格式。 在第三行中,na 值被删除,因为我不想显示它们。 Tally() 用于获取 n 值,该值可用于显示沿 y-axis 的计数。 在第四行,有必要re-order 到age-brackets,以便它们按时间顺序沿着x-axis 显示。其余的行帮助开发了一个基本的条形图。

age_plot <- data_split %>% select(`6-9`:`19-23`) %>%
   pivot_longer(., cols = c(`6-9`:`19-23`), names_to = "Var", values_to = "Val") %>%
   drop_na() %>% group_by(Var, Val) %>% tally() %>%
   ggplot(aes(x = factor(Var, level = c("6-9", "10-13", "14-18", "19-23")), y = n, 
   fill = factor(Val, level = c("child 1", "child 2", "child 3", "child 4")))) +
   geom_bar(stat = "identity", position = position_dodge(width = 0.9)) +
   theme_classic() + labs(fill = "Child", x = "Age", y = "Number")

age_plot

结果看起来像 this。 (显然这张图看起来有点奇怪,数据点太少了,但实物看起来不错!)

更新:“position_dodge”更改为“position_dodge2”,“geom_bar”中的“preserve = 'single'”因此每个单独的柱现在都是宽度相同。

答案在问题正文中,但也粘贴在这里,以防有用。

在下面的代码中,data_to_split 对应于问题中显示的 table 的小片段。

可复制版本:

structure(list(x10a.6.9 = c("child 2;child 3", NA, "child 3;child 4", 
NA), x10a.10.13 = c(NA, "child 1", "child 2", "child 1;child 2"
), x10a.14.18 = c("child 1", NA, NA, NA), x10a.19.23 = c(NA, 
NA, "child 1", NA)), row.names = c(NA, -4L), class = "data.frame")
    library(tidyr)
    library(dplyr)
    library(ggplot2)
    data_split <- data_to_split %>% 
    separate_rows(x10a.6.9:x10a.19.23, sep = ";") %>% 
    select(x10a.6.9:x10a.19.23) %>% na_if(., "") %>%
    mutate_all(funs(as.factor))

有必要使用 tidyr 的 separate_rows 函数,因为一个单元格内可能会出现多个响应(例如,一个单元格可以读取 'child 1;child 2')分隔符“;”用于将这些单元格分成多行。

na_if 用于将作为因子读取的空格转换为 NA 值。

在下面的代码中,添加了新列。这些列只是为已读入 R 的列提供了新名称。旧名称很难看且更难使用。

    data_split$`6-9` <- data_split$x10a.6.9
    data_split$`10-13` <- data_split$x10a.10.13
    data_split$`14-18` <- data_split$x10a.14.18
    data_split$`19-23` <- data_split$x10a.19.23

在下面的前两行代码中,选择了所有包含年龄段的相关列。然后将数据从宽格式转换为长格式。 在第三行中,na 值被删除,因为我不想显示它们。 Tally() 用于获取可用于沿 y 轴显示计数的 n 值。 在第四行中,有必要重新排列年龄段,以便它们按时间顺序沿 x 轴显示。其余的行帮助开发了一个基本的条形图。

age_plot <- data_split %>% select(`6-9`:`19-23`) %>%
       pivot_longer(., cols = c(`6-9`:`19-23`), names_to = "Var",  values_to = "Val") %>%
       drop_na() %>% group_by(Var, Val) %>% tally() %>%
       ggplot(aes(x = factor(Var, level = c("6-9", "10-13", "14-18", "19-23")), y = n, 
       fill = factor(Val, level = c("child 1", "child 2", "child 3", "child 4")))) +
       geom_bar(stat = "identity", position = position_dodge2(width = 0.9, preserve = "single")) +
       theme_classic() + labs(fill = "Child", x = "Age", y = "Number")

age_plot

结果看起来像 this。 (显然这张图看起来有点奇怪,数据点太少了,但实物看起来不错!)