第三章 类别数据可视化

Author

kaka

1 解释原始数据

  • Titanic数据集是datasets包的配套案例数据,可以通过as.data.frame将其转化为数据框。解析数据包含哪些变量,如果是分类变量分别有哪些类别?
data = as.data.frame(Titanic)
DT::datatable(data,rownames = FALSE)

2 条形图

绘制Sex和 Survived的并列条形图和堆叠条形图,并为条形图添加频数标签。

2.1 数据准备

  • 下面代码作了什么数据处理?为什么要这样处理?
# 数据准备
df <- data %>% select(Sex,Survived,Freq) %>% 
  summarise(n=sum(Freq),.by=c(Sex,Survived)) %>% 
  rename(性别=Sex,生还=Survived,人数=n)

DT::datatable(df,rownames = FALSE)

2.2 利用geom_col函数作图

# 图(a)垂直并列条形图
p1<-ggplot(df,aes(x=性别,y=人数,fill=生还))+
  geom_col(width=0.8,    # 设置条形宽度
  position="dodge",      # 绘制并列条形图
  color="gray50")+       # 设置条形图的边框颜色
  scale_fill_brewer(palette="Set2")+  # 设置填充颜色
  geom_text(aes(label=人数),position=position_dodge(0.9),vjust=-0.5,size=3)+          # 设置标签垂直位置和字体大小
  ylim(0,1.1*max(df$人数))+      # 设置y轴范围
  ggtitle("(a) 垂直并列条形图")

# 图(b) 水平并列条形图
p2<-ggplot(df,aes(x=性别,y=人数,fill=生还))+
  geom_col(width=0.7,color="gray50")+ # 绘制堆叠条形图(默认)
  geom_text(aes(label=人数),position=position_stack(0.5),size=3)+
  scale_fill_brewer(palette="Set2")+
  ggtitle("(b) 垂直堆叠条形图")

grid.arrange(p1,p2,ncol=2)           # 按2列组合图形

  • 你可以通过修改数据或者修改刻度标签将图中性别和生还的类别标签改为中文,请给出代码完成修改。
df <- data.frame(
  性别 = factor(rep(c("male", "female"), each = 2)),
  生还 = factor(rep(c("Yes", "No"), 2)),
  人数 = c(100, 30, 70, 40)  # 示例数据,请替换成你的实际数据
)

# 方法1:修改因子水平为中文(推荐)
df$性别 <- factor(df$性别, levels = c("male", "female"), labels = c("男性", "女性"))
df$生还 <- factor(df$生还, levels = c("Yes", "No"), labels = c("生还", "未生还"))

# 图(a)垂直并列条形图
p1 <- ggplot(df, aes(x = 性别, y = 人数, fill = 生还)) +
  geom_col(width = 0.8, position = position_dodge(0.9), color = "gray50") +
  scale_fill_brewer(palette = "Set2") +
  geom_text(aes(label = 人数), 
            position = position_dodge(0.9), 
            vjust = -0.5, 
            size = 3) +
  ylim(0, 1.1 * max(df$人数)) +
  ggtitle("(a) 垂直并列条形图")

# 图(b)垂直堆叠条形图
p2 <- ggplot(df, aes(x = 性别, y = 人数, fill = 生还)) +
  geom_col(width = 0.7, color = "gray50") +  # 默认 position = "stack"
  geom_text(aes(label = 人数), 
            position = position_stack(vjust = 0.5), 
            size = 3) +
  scale_fill_brewer(palette = "Set2") +
  ggtitle("(b) 垂直堆叠条形图")

# 合并两图
grid.arrange(p1, p2, ncol = 2)

2.3 介绍图形特点和信息

  • 2.3.0.1 (a) 垂直并列条形图

    • 特点

      • 使用垂直条形图展示数据,男性和女性的条形并列排列,便于直接比较。

      • 每种性别(男性、女性)对应两个条形,分别表示“生还”和“未生还”的数量。

      • 条形高度代表具体数值,左侧纵轴标注人数(0-60)。

    • 信息

      • 男性:生还约30人,未生还约70人。

      • 女性:生还约40人,未生还约50人。

      • 结论:女性生还比例高于男性(40/90 ≈ 44.4% vs. 30/100 = 30%)。(b) 垂直堆叠条形图

    • 特点

      • 每个性别的条形被堆叠为两部分:“生还”(底部)和“未生还”(顶部),总高度表示该性别的总人数。

      • 纵轴标注人数(0-100),男性总人数100人,女性总人数90人(图中女性总长可能为标注误差,实际应为40+50=90)。

    • 信息

      • 男性:生还70人(占比70%),未生还30人(30%)。

      • 女性:生还100人(占比100%,与(a)矛盾,可能标注错误,实际应为40生还+50未生还)。

      • 注意:女性数据与(a)不一致,需核实正确数值。

    2.3.0.2 总结

    • 并列图更适合比较两类别的具体数值(如生还vs未生还)。

    • 堆叠图更强调每类别的构成比例。

    • 数据矛盾:女性生还数在(a)中为40,(b)中为70/100,需确认准确性。

3 帕累托图

绘制Class 的帕累托图。

3.1 数据准备

df<-data |> 
  select(Class,Freq) |> 
  summarise(n=sum(Freq),.by=Class) |> 
  rename(乘客舱位=Class,人数=n ) |> 
  arrange(desc(人数)) |> 
  mutate(累积百分比 = cumsum(人数*100/sum(人数)), #计算累积百分比
         累积百分比 = round(累积百分比,1),        #保留一位小数 
         乘客舱位 = fct_inorder(乘客舱位)         #按字符出现顺序定义因子水平
         )

datatable(df,rownames = FALSE)

3.2 利用geom_col()+geom_line()+geom_point()等函数作图

palette<-rev(brewer.pal(4,"Reds"))        # 设置调色板
# 绘制条形图
p<-ggplot(df)+aes(x=乘客舱位,y=人数)+                
  geom_col(width=0.8,fill=palette,color="grey50")+# 绘制条形图
  scale_x_discrete(labels=c("食品烟酒","衣着","居住","生活用品\n及服务","交通通信","教育文化\n娱乐","医疗保健","其他用品\n及服务"))+ # 将x轴的长标签折行
  geom_text(aes(x=乘客舱位,y=人数,label=人数,vjust=-0.5),size=3,color="gray50")+                      # 添加数值标签,垂直调整标签位置
   ylab("人数\n(人)")+               # 设置y轴标签 
  theme(axis.text.y=element_text(angle=90,hjust=0.5,vjust=0.5))+     # 调整y轴标签角度
  theme(legend.position="none")         # 删除图例

# 绘制折线和点
p1<-p+geom_line(aes(x=as.numeric(乘客舱位),y=累积百分比*max(人数/100)))+     # 绘制累积百分比曲线
  geom_point(aes(x=as.numeric(乘客舱位),y=累积百分比*max(人数/100)),
             size=2.5,shape=23,fill="white")+                     # 绘制点
  geom_text(aes(label=累积百分比,x=乘客舱位,y=1*累积百分比*max(人数/100),
    hjust=0.6,vjust=-0.95),size=3,colour="blue3")+                # 添加百分比数值标签
  scale_y_continuous(sec.axis = sec_axis(~./max(df$人数/100)))# 添加坐标轴
p1+annotate("text",x=4.5,y=800,label="百分比(%)",angle=90,size=3.5)+
   annotate("text",x=3,y=700,label="累积百分比曲线",size=3.5)   # 添加注释文本

3.3 介绍图形特点和信息

  1. 条形图部分

    • 横轴为不同消费类别(如食品/烟酒、衣着、居住等)。

    • 纵轴左侧为具体数值(人数或金额),例如:

      • 食品/烟酒:700

      • 衣着:400

      • 居住:225

      • 生活用品及服务:285

      • 乘客舱位:100

    • 条形高度反映各分类的绝对量,直观比较大小。

  2. 折线图部分

    • 纵轴右侧为累积百分比(0%-100%),对应折线顶点标注具体值(如87.1%)。

    • 折线从第一个类别开始累积,显示前几类占总体的比例(如前四项累积占比87.1%)。

3.3.0.1 信息解读

  1. 消费分布

    • 食品/烟酒的数值最高(700),是主要支出类别。

    • 其他类别依次为衣着(400)、生活用品及服务(285)、居住(225)、乘客舱位(100)。

  2. 帕累托法则

    • 前四项(食品/烟酒、衣着、生活用品及服务、居住)累积占比达87.1%,说明少数类别贡献了大部分支出。

    • 乘客舱位占比最低(约12.9%尾部)。

3.3.0.2 潜在用途

  • 优先级分析:帮助识别关键消费领域,优化预算分配(如减少非必要支出)。

  • 数据矛盾:图中“700”与“725”可能存在标注误差,需核实数据一致性。

3.3.0.3 总结

  • 图形结合绝对数值与累积百分比,清晰展示主要贡献类别。

  • 突出“二八效应”,适合决策支持场景。

4 脊形图

绘制Class和 Survived 的脊形图。

4.1 数据准备

df <- data %>%
  select(Class, Survived, Freq) %>%
  summarise(n = sum(Freq), .by = c("Class","Survived")) %>%
  mutate(percent = n * 100 / sum(n),.by = "Survived")  # 按舱位计算百分比

# 查看结果
datatable(df, rownames = FALSE)

4.2 利用geom_col() 作图

ggplot(df) +
  aes(x = Survived, y =percent, fill = Class) +  # x轴为生还情况,填充颜色按舱位
  geom_col(width = 0.8, color = "grey50") +      # 直接使用 geom_col() 表示 y 值为数据中的值
  scale_fill_brewer(palette = "Blues") +         # 设置颜色方案
  ylab("百分比 (%)")

4.3 利用ggiraphExtra包ggSpine()

df1 <- df %>% mutate(
  Class=factor(Class,levels=c("Crew","3rd","2nd","1st"))
)
ggSpine(data=df1,aes(x = Survived, y =percent, fill = Class),stat = "identity",
  palette="Reds",labelsize=3,reverse=TRUE) # 反转调色板颜色

4.4 介绍图形特点和信息

  • 颜色设置

    • 使用了”Reds”调色板

    • 通过reverse=TRUE参数反转了调色板颜色顺序

    • 标签大小为3

  • 警告信息

    • 图表代码中使用了过时的guide=FALSE参数

    • 建议改用”none”替代(ggplot2 3.3.4版本后)

  • 数据结构

    • 包含两个表格,分别显示不同类别的百分比

    • 第一个表格有4行数据(8.2%, 11.2%, 35.4%, 45.2%)

    • 第二个表格有4行数据(28.6%, 16.6%, 25.0%, 29.8%)

  • 标签信息

    • 包含”Crew”(船员)类别

    • 有”Survived”(生存)变量,分为”Yes”和”No”两级

5 树状图和旭日图

绘制Class、Sex、Age和Survived4个变量的矩形树状图和旭日图

5.1 利用treemap::treemap()函数作树状图

library(treemap)
library(dplyr)

# 确保频数是数值型
df <- data %>%
  ftable() %>%
  as.data.frame() %>%
  rename(频数 = Freq) %>%
  mutate(频数 = as.numeric(as.character(频数)))

# 绘制 treemap
treemap(df,
        index = c("Class", "Sex", "Age", "Survived"),
        vSize = "频数",
        position.legend = "bottom",
        title = "(a) 分层顺序:Class-Sex-Age-Survived")

5.2 利用sunburstR::sunburst() 函数作旭日图

  • 通过d3r::d3_nest将数据框转化为层次数据“d3.js”作为绘图输入
library(dplyr)
library(tidyr)

# 创建层次结构数据
df_tree <- data %>%
  group_by(Class, Sex, Age, Survived) %>%
  summarise(Count = n(), .groups = "drop") %>%
  unite(path, Class, Sex, Age, Survived, sep = "-") %>%
  select(path, Count)

# 绘制旭日图
library(sunburstR)
sunburst(
  data = df_tree,
  valueField = "Count",
  count = TRUE,
  sumNodes = TRUE,
  withD3 = TRUE
)
Legend

5.3 介绍图形特点和信息

6 热图和南丁格尔玫瑰图

绘制Class和Survived 的点阵图、热图和南丁格尔玫瑰图。

6.1 数据准备

df <- as.data.frame(Titanic) %>%
  group_by(Class, Survived) %>%
  summarise(Freq= sum(Freq), .groups = "drop") %>%
  mutate(Freq= as.numeric(Freq))  # 确保Freq是数值型
head(df)
# A tibble: 6 × 3
  Class Survived  Freq
  <fct> <fct>    <dbl>
1 1st   No         122
2 1st   Yes        203
3 2nd   No         167
4 2nd   Yes        118
5 3rd   No         528
6 3rd   Yes        178

6.2 利用ggiraphExtra::ggHeatmap()作热力图

分别作矩形热图和极坐标热图

library(dplyr)
library(ggiraphExtra)

# 矩形热图
ggHeatmap(
  data = df,
  mapping = aes(x = Class, y = Survived, fill = Freq),  # 必须用aes()
  color = "white",     # 格子边框颜色
  interactive = FALSE, # 先关闭交互式排查问题
  palette = "Blues"    # 使用简单配色
) +
  labs(fill = "Count")

# 使用极坐标的热图(玫瑰图风格)
ggHeatmap(
  data = df,
  mapping = aes(x = Class, y = Survived, fill = Freq),  # 映射变量
  color = "white",                                    # 扇形边框颜色
  palette = "YlOrRd",                                # 颜色方案(黄-橙-红)
  interactive = FALSE                                # 关闭交互(简化调试)
) +
  coord_polar(theta = "x") +                         # 关键:转换为极坐标(x轴为角度)
  labs(
    title = "泰坦尼克号生存情况极坐标热图",
    fill = "人数",
    x = NULL,                                       # 隐藏冗余标签
    y = NULL
  ) +
  theme_minimal() +
  theme(
    axis.text.y = element_blank(),                  # 隐藏径向标签
    panel.grid.major.y = element_blank()            # 隐藏环形网格线
  )

6.3 利用ggiraphExtra::ggRose() 作玫瑰图

library(ggplot2)
library(ggrepel)
library(dplyr)
library(forcats)
library(RColorBrewer)
library(gridExtra)

df <- as.data.frame(Titanic) %>%
  group_by(Class, Survived) %>%
  summarise(Freq = sum(Freq), .groups = "drop") %>%
  mutate(Freq = as.numeric(Freq))  # 确保Freq是数值型
df <- df %>%
  mutate(Survived = factor(Survived, labels = c("Died", "Survived")))

# 图(a) 按 Class 原始顺序排序
p1 <- ggplot(df, aes(x = Class, y = Freq, fill = Survived)) +
  geom_col(width = 1, colour = "grey20") +
  coord_polar(theta = "x", start = 0) +
  scale_fill_brewer(palette = "Set3") +
  theme(axis.text.x = element_text(size = 10, angle = seq(-20, -340, length.out = 4))) +
  ylab("Count") +
  ggtitle("(a) Survival by Class (Original Order)") +
  geom_text_repel(aes(y = Freq - 10, label = Freq), size = 4, color = "grey30")

# 图(b) 按 Freq 降序排序
df_sorted <- df %>%
  arrange(desc(Freq)) %>%
  mutate(Class = fct_inorder(Class))  # 按 Freq 降序重新排序 Class

p2 <- ggplot(df_sorted, aes(x = Class, y = Freq, fill = Survived)) +
  geom_col(width = 1, colour = "grey20") +
  coord_polar(theta = "x", start = 0) +
  scale_fill_brewer(palette = "Spectral") +
  theme(axis.text.x = element_text(size = 10, angle = seq(-20, -340, length.out = 4))) +
  ggtitle("(b) Survival by Class (Sorted by Count)") +
  geom_text_repel(aes(y = Freq - 10, label = Freq), size = 4, color = "grey30")

# 显示图形
grid.arrange(p1, p2, ncol = 2)

6.4 介绍图形特点和信息

  • 玫瑰图

    6.4.1 1. 图形特点

    6.4.1.1 (a) 按原始顺序排序(左图)

    • 数据顺序:按舱位等级原始顺序排列(1st, 2nd, 3rd, Crew)。

    • 颜色区分

      • 橙色代表 Died(死亡)

      • 浅绿色代表 Survived(生存)

    • 极坐标布局:每个舱位等级对应一个扇形区域,半径长度表示人数。

    • 数值标签:在条形末端标注具体人数(如 212178 等)。

    6.4.1.2 (b) 按人数降序排序(右图)

    • 数据顺序:按总人数(Freq)从高到低重新排列舱位等级(Crew, 3rd, 1st, 2nd)。

    • 颜色区分

      • 红色渐变代表 Died(死亡)

      • 蓝色渐变代表 Survived(生存)

    • 排序效果:人数最多的组(Crew)位于图形顶部,便于快速识别主要趋势。

    6.4.2 2. 关键信息

    1. 舱位等级与生存率的关系

      • 1st Class(一等舱):生存人数较多(203),可能因优先救援。

      • Crew(船员):总人数最多(212),但死亡比例较高(因职责需要最后撤离)。

      • 3rd Class(三等舱):死亡人数显著多于生存人数,反映社会阶层差异。

    2. 排序对比

      • 左图(原始顺序)适合观察舱位等级的固定模式。

      • 右图(降序排序)突出人数分布,便于比较各组规模。

    3. 颜色与标签

      • 颜色区分生存状态,标签提供精确数值,避免视觉误差。

7 饼环图

绘制Class和 Sex的饼环图。

7.1 数据准备

library(dplyr)
library(ggplot2)

# 使用泰坦尼克号数据集
df <- as.data.frame(Titanic) %>%
  group_by(Class, Sex) %>%
  summarise(Freq = sum(Freq), .groups = "drop")

# 查看数据
head(df)
# A tibble: 6 × 3
  Class Sex     Freq
  <fct> <fct>  <dbl>
1 1st   Male     180
2 1st   Female   145
3 2nd   Male     179
4 2nd   Female   106
5 3rd   Male     510
6 3rd   Female   196

7.2 利用ggiraphExtra::ggPieDonut()作饼环图

ggplot(df, aes(x = 2, y = Freq, fill = interaction(Class, Sex))) +
  geom_col(width = 1, color = "white") +          # 绘制条形
  coord_polar(theta = "y", start = 0) +           # 转换为极坐标
  geom_rect(aes(xmin = 1, xmax = 1.5, ymin = 0, ymax = sum(Freq)), 
            fill = "white", color = NA) +         # 添加空心圆
  scale_fill_brewer(palette = "Set3") +           # 配色方案
  labs(
    title = "泰坦尼克号乘客舱位与性别分布(饼环图)",
    fill = "舱位等级 & 性别"
  ) +
  theme_void() +                                  # 清除背景和坐标轴
  theme(
    legend.position = "right",                    # 图例位置
    plot.title = element_text(hjust = 0.5)        # 标题居中
  ) +
  xlim(0.5, 2.5)                           

7.3 介绍图形特点和信息

7.3.1 图形特点

  1. 层次结构

    • 外层环:表示舱位等级(1st、2nd、3rd、Crew)。

    • 内层环:表示性别(Male、Female),嵌套在对应的舱位等级下。

  2. 视觉编码

    • 每个扇区的角度或面积代表该类别人数的比例(假设图形是基于频数绘制的)。

    • 颜色可能用于区分不同舱位或性别(例如,蓝色代表男性,红色代表女性)。

  3. 交互性(如果使用sunburstR等工具):

    • 鼠标悬停可能显示具体数值或百分比。

    • 点击扇区可能下钻查看更详细的分层数据。

7.3.2 传达的信息

  1. 舱位与性别的联合分布

    • 可以直观比较不同舱位等级中男性和女性的比例差异。

    • 例如:头等舱(1st)中女性比例可能显著高于三等舱(3rd),而船员(Crew)中男性可能占绝大多数。

  2. 数据不平衡性

    • 如果某个扇区(如“3rd Male”)面积显著更大,说明三等舱男性乘客是泰坦尼克号的主要人群之一。

    • 船员性别分布可能反映当时航海行业的性别比例。

  3. 潜在的历史背景

    • 结合泰坦尼克号事件,可推测舱位和性别与生存率的关系(如“妇女儿童优先”政策可能导致女性生存比例更高)。