第三章 类别数据可视化

Author

kaka

1 解释原始数据

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

答:Titanic数据集是R语言datasets包中的一个经典数据集,记录了泰坦尼克号上乘客的生存情况及相关信息。使用as.data.frame(Titanic)可将其转换为数据框格式,转换后的数据包含以下变量:分类变量及类别:Class:1st, 2nd, 3rd, Crew,Sex:Male, Female,Age:Child, Adult,Survived:No, Yes

  • 数值变量:Freq(频数)
data = as.data.frame(Titanic)
DT::datatable(data,rownames = FALSE)

2 条形图

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

2.1 数据准备

  • 下面代码作了什么数据处理?为什么要这样处理?

答:这段代码对 Titanic 数据集进行了分组汇总统计,目的是计算不同性别(Sex)与生还情况(Survived)的组合人数,并用交互式表格展示。

原因:

  1. 简化数据
    原始 Titanic 数据是 4 维交叉表(Class × Sex × Age × Survived),通过聚焦 SexSurvived 降低复杂度,便于分析性别对生还的影响。

  2. 聚合统计
    原始数据中相同组合(如 Male/No)可能分散在多行,sum(Freq) 确保正确计算总人数。

  3. 提升可读性
    中文列名和交互式表格更适合展示结果(尤其在报告或 Shiny 应用中)。

# 数据准备
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列组合图形

  • 你可以通过修改数据或者修改刻度标签将图中性别和生还的类别标签改为中文,请给出代码完成修改。
# 图(a)垂直并列条形图
p1 <- ggplot(df, aes(x=性别, y=人数, fill=生还)) +
  geom_col(width=0.8, position="dodge", color="gray50") +
  scale_fill_brewer(palette="Set2",
                   labels = c("是", "否")) + # 修改图例标签
  scale_x_discrete(labels = c("男性", "女性")) + # 修改x轴标签
  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") +
  scale_fill_brewer(palette="Set2",
                   labels = c("是", "否")) +
  scale_x_discrete(labels = c("男性", "女性")) +
  geom_text(aes(label=人数), position=position_stack(0.5), size=3) +
  ggtitle("(b) 垂直堆叠条形图") 

grid.arrange(p1, p2, ncol=2)

2.3 介绍图形特点和信息

  • 答:图 (a) 垂直并列条形图:同一性别“是否生还”分组并列显示,X轴为性别(“男性”、“女性”),分类变量。Y轴表示人数,为数值变量。通过图形,可以比较同一性别下的生还情况。例如,若男性“未生还”人数显著高于“生还”人数,体现性别对生存率的影响。图 (b) 垂直堆叠条形图:表示同一性别的“生还”与“未生还”叠加的总人数,每个条形总高度表示该性别的总人数(生还 + 未生还),通过颜色区块的高度比例,直观对比不同性别下生还/未生还的占比。例如,女性生还比例(彩色部分占比)可能高于男性。

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()等函数作图

library(ggplot2)
library(scales)
# 绘图代码
ggplot(df, aes(x = 乘客舱位)) +
  # 柱状图:各舱位人数
  geom_col(aes(y = 人数), fill = "#4E79A7", width = 0.6, alpha = 0.8) +  
  # 折线图:累积百分比(次Y轴)
  geom_line(
    aes(y = 累积百分比 * max(人数) / 100, group = 1),  # 比例转换
    color = "#E15759", 
    linewidth = 1.2
  ) +
  # 散点图:标记累积百分比点
  geom_point(
    aes(y = 累积百分比 * max(人数) / 100), 
    color = "#E15759", 
    size = 3
  ) +
  # 双Y轴设置
  scale_y_continuous(
    name = "人数",  # 主Y轴
    sec.axis = sec_axis(
      ~ . * 100 / max(df$人数),  # 次Y轴转换回百分比
      name = "累积百分比 (%)",
      labels = scales::percent_format(scale = 1)  # 显示为百分比
    )
  ) +
  # 添加数据标签
  geom_text(
    aes(y = 人数, label = 人数), 
    vjust = -0.5, 
    size = 3.5,
    color = "black"
  ) +
  geom_text(
    aes(y = 累积百分比 * max(人数) / 100, label = paste0(累积百分比, "%")),
    vjust = -1, 
    size = 3.5,
    color = "#E15759"
  ) +
  # 主题美化
  labs(
    title = "各舱位乘客人数及累积百分比",
    x = "乘客舱位"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 0, hjust = 0.5),
    plot.title = element_text(hjust = 0.5, face = "bold"),
    panel.grid.major.y = element_line(color = "gray90")
  )

3.3 介绍图形特点和信息

  • 答:主图表柱状图(蓝色)表示各舱位的乘客人数次图表折线图 + 散点图(红色)表示累积百分比(从第一个舱位到当前舱位的累计占比)。双Y轴:左侧Y轴为人数,右侧Y轴为累积百分比,X轴表示乘客舱位(如 “3等舱”、“2等舱”、“1等舱”),按人数从高到低排序。柱状图高度代表该舱位的实际人数折线趋势,从左上到右下,表示累积百分比逐渐增加(如 3等舱占50%,加上2等舱后达80%,最终1等舱达100%)。通过图形可直观看出哪个舱位乘客最多,可用于分析乘客分布是否均衡

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 = "Class")

datatable(df,rownames = FALSE)

4.2 利用geom_col() 作图

library(ggplot2)

# 计算每个 Class 的总人数(用于宽度)
class_totals <- df %>% 
  summarise(total = sum(n), .by = Class)

# 合并总人数到原始数据
df_spine <- df %>% 
  left_join(class_totals, by = "Class") %>%
  mutate(width = total / sum(total))  # 标准化宽度

# 绘制脊形图
ggplot(df_spine, aes(x = Class, y = percent, width = width, fill = Survived)) +
  geom_col(position = "fill") +  # position="fill" 确保高度标准化为比例
  scale_y_continuous(labels = scales::percent) +  # y轴显示为百分比
  labs(title = "Survival Distribution by Class (Spine Plot)",
       x = "Class",
       y = "Proportion Survived",
       fill = "Survived") +
  theme_minimal()

4.3 利用ggiraphExtra包ggSpine()

# 加载必要的包
library(dplyr)          # 数据处理
library(DT)             # 交互式表格
library(ggiraphExtra)   # 用于 ggSpine()

# 显示数据(可选)
datatable(df, rownames = FALSE)
# 使用 ggSpine() 绘制脊形图
ggSpine(
  data = df,
  aes(x = Survived, y = percent, fill = Class),
  stat = "identity",    # 直接使用数据值
  palette = "Reds",     # 使用红色调色板
  labelsize = 3,        # 标签大小
  reverse = TRUE        # 反转颜色渐变
)

4.4 介绍图形特点和信息

  • 答:图形采用并列堆积柱形呈现,两根柱子分别对应 “未幸存(No)” 和 “幸存(Yes)” 情况。每个柱子按舱位等级(头等舱、二等舱、三等舱、船员)分层堆积,各层用不同颜色区分,直观展示各部分占比。从图中可以得到,未幸存方面,船员和三等舱占比较高,分别为 30.8%、30.3% ,头等舱最低,为 15.2% 。幸存方面,头等舱占比最高,达 40.8% ,船员和三等舱较低,分别为 15.7%、16.5% 。整体反映出泰坦尼克号事件中,舱位等级与幸存率存在关联。

5 树状图和旭日图

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

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

df<-data%>%
  rename(频数=Freq) # 将Freq命名为频数

datatable(df,rownames = FALSE)
# 绘制树状图
treemap(
  df,
  index = c("Class", "Sex", "Age", "Survived"),
  vSize = "频数",
  palette = "Set2",
  title = "乘客特征分布",
  fontfamily.title = "sans",
  fontsize.labels = c(12, 10, 8, 6),
  align.labels = list(c("center", "center"))
)

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

  • 通过d3r::d3_nest将数据框转化为层次数据“d3.js”作为绘图输入
library(d3r)
df<-data%>%select("Age","Sex","Class","Survived","Freq")  # 根据需要调整列变量的位置
df_tree<-d3_nest(df,value_cols="Freq")             # 将数据框转换为“d3.js”层次结构
datatable(df,rownames = FALSE)
# 绘制旭日图
 library(sunburstR)
sunburst(data=df_tree, valueField="Freq", 
         count=TRUE, sumNodes=TRUE,
         colors = list(range = c("#FF6B6B", "#4ECDC4", "#45B7D1", "#FFA07A")))
Legend

5.3 介绍图形特点和信息

从圆心向外,每一环代表一个变量层级(如 Class → Sex → Age → Survived),内层是外层的子类别。每个扇区的大小由 valueField="Freq" 的数值决定,面积越大表示频数越高,同一层级下的扇区面积按比例分配(如”男性”和”女性”的面积比等于二者的频数比)。

6 热图和南丁格尔玫瑰图

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

6.1 数据准备

df<-data%>%select(Class,Survived,Freq) %>% 
  summarise(n=sum(Freq),.by=c(Class,Survived))
datatable(df,rownames = FALSE)

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

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

library(ggiraphExtra)

# 矩形热图
rect_heatmap <- ggHeatmap(
  data = df,
  mapping = aes(x = Class, y = Survived, fill = n),  # 映射变量
  addlabel = TRUE,                                   # 显示数值标签
  palette = "Reds",                                  # 红色渐变
  color = "white",                                   # 单元格边框颜色
  xlab = "舱位等级",                                 # x轴标签
  ylab = "生还状态",                                 # y轴标签
  main = "舱位与生还人数(矩形热图)"                # 标题
) + 
  theme_minimal()                                    # 简洁主题

print(rect_heatmap)

# 极坐标热图(无重复标度)
polar_heatmap <- ggHeatmap(
  data = df,
  mapping = aes(x = Class, y = Survived, fill = n),
  polar = TRUE,
  palette = "Blues",               # 内置配色方案
  main = "舱位与生还人数(极坐标热图)"
) +
  theme(legend.position = "bottom") # 仅调整图例位置

print(polar_heatmap)

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

library(ggiraphExtra)
library(dplyr)
library(forcats)  # 用于因子排序
library(gridExtra) # 多图排版

# 数据准备
df <- data %>% 
  select(Class, Survived, Freq) %>% 
  summarise(n = sum(Freq), .by = c(Class, Survived)) %>% 
  mutate(Class = fct_inorder(Class))  # 保持舱位等级原始顺序

# 自定义标签角度(8个分类需调整)
myangle <- seq(-20, -340, length.out = length(unique(df$Class)))

# 图(a):x轴为舱位等级
p1 <- ggRose(
  data = df,
  mapping = aes(x = Class, y = n, fill = Survived),
  stat = "identity",
  palette = "Reds",
  reverse = TRUE
) +
  ylab("乘客数量") +
  guides(fill = guide_legend(nrow = 2, title = NULL)) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(size = 10),
    axis.text.x = element_text(size = 8, color = "red3", angle = myangle)
  ) +
  ggtitle("(a) 按舱位等级分布")

# 图(b):x轴为生还状态
p2 <- ggRose(
  data = df,
  mapping = aes(x = Survived, y = n, fill = Class),
  stat = "identity",
  palette = "Blues",
  reverse = FALSE
) +
  ylab("乘客数量") +
  guides(fill = guide_legend(nrow = 2, title = NULL)) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(size = 10),
    axis.text.x = element_text(size = 8, color = "blue3")
  ) +
  ggtitle("(b) 按生还状态分布")

# 双图合并输出
grid.arrange(p1, p2, ncol = 2)

6.4 介绍图形特点和信息

6.4.1 按舱位等级分布(左图)

  • 特点:以极坐标形式呈现,用不同颜色区分幸存(Yes )和未幸存(No )情况。

  • 信息:可看出 Crew 和 3rd 的乘客数量较多,且未幸存(橙色)占比较大;1st 和 2nd 乘客数量相对较少,幸存(浅橙色)与未幸存分布有差异,直观展示舱位等级与幸存情况的关联。

6.4.2 按生还状态分布(右图)

  • 特点:同样是极坐标,用不同灰度蓝色区分舱位等级。

  • 信息:能明显看到未幸存(No )的乘客数量远多于幸存(Yes )。不同舱位在幸存和未幸存中的分布有别,Crew 在未幸存中占比较大,反映出不同舱位等级的生还差异。

7 饼环图

绘制Class和 Sex的饼环图。

7.1 数据准备

df <- data %>% select(Sex,Class,Freq) %>% 
  summarise(n=sum(Freq),.by=c(Sex,Class)) %>%
  rename(性别=Sex,乘客舱位=Class,人数=n)
  
DT::datatable(df,rownames = FALSE)

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

library(ggiraphExtra)
p1<-ggPieDonut(
  data=df,aes(pies=性别,donuts=乘客舱位,count =人数),
  title="(a) 性别为饼图,乘客舱位为环形图")

# 使用gridExtra排列图表
gridExtra::grid.arrange(p1, ncol = 1) # 单列显示图表 

7.3 介绍图形特点和信息

性别分布

  • Male(男性):占比 78.6% ,在图中以大面积红色扇形呈现,是主体部分。

  • Female(女性):占比 21.4% ,以浅蓝色扇形显示,占比较小。

7.3.1 乘客舱位分布

  • Male 对应的舱位

    • Crew(船员):占 Male 群体的 39.2% ,是男性中占比最大的舱位类别。

    • 3rd(三等舱):占 23.2% 。

    • 2nd(二等舱):占 8.1% 。

    • 1st(头等舱):占 8.2% 。

  • Female 对应的舱位

    • Crew(船员):占 Female 群体的 1% 。

    • 3rd(三等舱):占 8.9% 。

    • 2nd(二等舱):占 4.8% 。

    • 1st(头等舱):占 6.6% 。

总体来看,男性在乘客中占比高,且男性船员占比突出;女性占比较低,各舱位分布相对分散。