第四章 数据分布可视化

Author

学号+姓名

1 解释原始数据

  • faithful是R语言中自带的一个经典数据集,它记录了美国黄石国家公园老忠实间歇泉(Old Faithful geyser)的喷发数据。这个数据集经常被用于统计教学和数据分析示例。

  • faithful数据集包含两个变量,共有272个观测值。

    data = faithful
    datatable(data,rownames = FALSE)
  • eruptions: 喷发持续时间,连续数值变量,以分钟为单位,范围:1.6分钟到5.1分钟。

  • waiting: 两次喷发之间的等待时间,连续数值变量,以分钟为单位,范围:43分钟到96分钟。

2 单变量直方图

2.1 绘图要求

  • 利用geom_histogram(aes(y=..density..))绘制eruptions的直方图,使用预设主题:mytheme;

  • 利用geom_rug()为直方图添加地毯图;

  • 利用geom_density()为直方图添加核密度曲线;

  • 利用annotate()在直方图标注峰度和偏度信息;

  • 利用geom_vline() 为直方图添加一条垂直的均值参考线;

  • 利用geom_point()在横轴上添加一个中位数参考点,并在点上方添加文字注释

2.2 作图代码

library(ggplot2)
library(dplyr)

# 预设主题
mytheme <- theme_bw() +
  theme(
    plot.title = element_text(hjust = 0.5),
    panel.grid.major = element_line(color = "grey90"),
    panel.grid.minor = element_blank()
  )

# 计算峰度和偏度
skewness <- function(x) {
  n <- length(x)
  (sum((x - mean(x))^3)/n)/(sum((x - mean(x))^2)/n)^(3/2)
}

kurtosis <- function(x) {
  n <- length(x)
  (sum((x - mean(x))^4)/n)/(sum((x - mean(x))^2)/n)^2 - 3
}

skew_val <- skewness(faithful$eruptions)
kurt_val <- kurtosis(faithful$eruptions)

# 计算均值和中位数
mean_val <- mean(faithful$eruptions)
median_val <- median(faithful$eruptions)

# 绘制图形
ggplot(faithful, aes(x = eruptions)) +
  geom_histogram(aes(y = ..density..), 
                 bins = 30, 
                 fill = "steelblue", 
                 color = "white", 
                 alpha = 0.8) +
  geom_rug(sides = "b", color = "steelblue", alpha = 0.3) +
  geom_density(color = "red", linewidth = 1) +
  geom_vline(xintercept = mean_val, 
             linetype = "dashed", 
             color = "darkgreen", 
             linewidth = 1) +
  geom_point(aes(x = median_val, y = 0), 
             shape = 17, 
             size = 4, 
             color = "purple") +
  annotate("text", 
           x = Inf, y = Inf, 
           label = paste0("偏度: ", round(skew_val, 2), "\n峰度: ", round(kurt_val, 2)),
           hjust = 1.1, vjust = 1.1, 
           size = 5, 
           color = "black") +
  annotate("text", 
           x = median_val, y = 0.1, 
           label = "中位数", 
           vjust = -0.5, 
           color = "purple") +
  labs(title = "Old Faithful 间歇泉喷发持续时间分布",
       x = "喷发持续时间 (分钟)", 
       y = "密度") +
  mytheme

2.3 图形观察和代码编写的心得体会

  • 本次实践利用 ggplot2faithful 数据集中的间歇泉喷发时间进行可视化分析,主要收获如下:

    1. 分布呈现双峰特征
      直方图与核密度曲线结合,清晰显示喷发时间集中在1.5-2分钟和4-4.5分钟两个区间,暗示可能存在两种不同的喷发模式。

    2. 统计量直观标注
      通过计算标注偏度(-0.42,左偏)和峰度(-1.5,平缓),量化了数据分布形态。均值线(绿色)与中位数点(紫色)的位置差异进一步验证左偏特性。

    3. 增强细节与可读性

    • 地毯图补充数据细节,避免分箱信息丢失

    • 自定义主题优化网格和标题排版

    • 关键注释(如中位数标签)提升解读效率

3 叠加直方图和镜像直方图

3.1 绘图要求

  • 绘制eruptionswaiting两个变量的叠加直方图和镜像直方图,使用预设主题:mytheme。

  • 将数据转化为长型数据再作叠加直方图,利用scale_fill_brewer()将叠加直方图配色方案改为set3

  • 镜像直方图中eruptions在正方向,waiting在负方向,直方数bins=30,并添加文字标签作标签。

  • 两种图都需要针对原始数据作图和标准标准化数据作图,可以使用scale()函数对变量标准化,分类标准化可以使用plyr::ddply()函数。

3.2 叠加直方图代码

library(ggplot2)
library(tidyr)
library(dplyr)
library(plyr)  # 用于 ddply 标准化

# 预设主题
mytheme <- theme_bw() +
  theme(plot.title = element_text(hjust = 0.5),
        panel.grid.major = element_line(color = "grey90"),
        panel.grid.minor = element_blank())

# 将数据转为长格式(便于叠加直方图)
faithful_long <- faithful %>%
  pivot_longer(cols = c(eruptions, waiting), 
               names_to = "variable", 
               values_to = "value")

# 标准化数据(按变量分类标准化)
faithful_std <- ddply(faithful_long, .(variable), transform, 
                      value_std = scale(value))
# 原始数据叠加直方图
p1 <- ggplot(faithful_long, aes(x = value, fill = variable)) +
  geom_histogram(aes(y = ..density..), 
                 bins = 30, 
                 alpha = 0.7, 
                 position = "identity") +
  scale_fill_brewer(palette = "Set3") +
  labs(title = "叠加直方图(原始数据)", 
       x = "值", y = "密度") +
  mytheme

# 标准化数据叠加直方图
p2 <- ggplot(faithful_std, aes(x = value_std, fill = variable)) +
  geom_histogram(aes(y = ..density..), 
                 bins = 30, 
                 alpha = 0.7, 
                 position = "identity") +
  scale_fill_brewer(palette = "Set3") +
  labs(title = "叠加直方图(标准化数据)", 
       x = "标准化值", y = "密度") +
  mytheme

3.3 镜像直方图代码

# 原始数据镜像直方图
p3 <- ggplot(faithful_long, aes(x = value)) +
  geom_histogram(data = subset(faithful_long, variable == "eruptions"), 
                 aes(y = ..density..), 
                 bins = 30, 
                 fill = "#66C2A5", 
                 alpha = 0.7) +
  geom_histogram(data = subset(faithful_long, variable == "waiting"), 
                 aes(y = -..density..), 
                 bins = 30, 
                 fill = "#FC8D62", 
                 alpha = 0.7) +
  geom_text(data = data.frame(x = c(2, 70), y = c(0.5, -0.02), 
            label = c("eruptions", "waiting")), 
            aes(x = x, y = y, label = label), 
            size = 5, 
            color = c("#66C2A5", "#FC8D62")) +
  labs(title = "镜像直方图(原始数据)", 
       x = "值", y = "密度") +
  mytheme

# 标准化数据镜像直方图
p4 <- ggplot(faithful_std, aes(x = value_std)) +
  geom_histogram(data = subset(faithful_std, variable == "eruptions"), 
                 aes(y = ..density..), 
                 bins = 30, 
                 fill = "#66C2A5", 
                 alpha = 0.7) +
  geom_histogram(data = subset(faithful_std, variable == "waiting"), 
                 aes(y = -..density..), 
                 bins = 30, 
                 fill = "#FC8D62", 
                 alpha = 0.7) +
  geom_text(data = data.frame(x = c(1.5, 1.5), y = c(0.4, -0.4), 
            label = c("eruptions", "waiting")), 
            aes(x = x, y = y, label = label), 
            size = 5, 
            color = c("#66C2A5", "#FC8D62")) +
  labs(title = "镜像直方图(标准化数据)", 
       x = "标准化值", y = "密度") +
  mytheme
# 使用 patchwork 包合并图形
library(patchwork)
(p1 + p2) / (p3 + p4) +
  plot_annotation(tag_levels = "A")

3.4 图形观察和代码编写的心得体会

本次实践通过叠加直方图和镜像直方图对比分析了faithful数据集中eruptions和waiting变量的分布特征,主要收获如下:

  1. 标准化是分布对比的关键。原始数据因量纲差异导致分布无法直接比较,通过分组标准化处理后,两变量的双峰特征和形态差异清晰显现。标准化既保留了分布形状,又消除了量纲影响。

  2. 镜像直方图是有效的对比工具。通过将waiting变量的密度值取负,实现了上下对称的可视化效果,避免了分布重叠问题,配合标签标注使对比更直观。

  3. 可视化细节决定效果。配色方案(Set3)、透明度(alpha=0.7)和分箱数(bins=30)的选择显著影响图形可读性,需根据数据特点调整优化。

  4. 分析需结合实际意义。标准化数据虽便于比较,但会丢失原始量纲信息,解读时需结合变量物理含义。

本次实践展示了如何通过ggplot2的多图层功能,实现复杂分布对比的可视化,为后续的数据分析和建模提供了重要参考。可视化不仅是技术实现,更是发现数据规律的有效途径。

4 核密度图

4.1 绘图要求

  • 绘制eruptions和 waiting两个变量的分组核密度图、分面核密度图和镜像核密度图。

  • 分组核密度图,采用geom_density(position="identity")

  • 分面核密度图,采用geom_density()+facet_wrap(~xx,scale="free")

  • 镜像核密度图中eruptions在正方向,waiting在负方向,直方数bins=30,并添加文字标签作标签。

  • 分组核密度图和镜像核密度图需要针对原始数据作图和标准标准化数据作图。

4.2 分组核密度图

library(ggplot2)
library(tidyr)
library(dplyr)
library(plyr)

# 预设主题
mytheme <- theme_bw() +
  theme(plot.title = element_text(hjust = 0.5),
        panel.grid.major = element_line(color = "grey90"),
        panel.grid.minor = element_blank())

# 将数据转为长格式
faithful_long <- faithful %>%
  pivot_longer(cols = c(eruptions, waiting), 
               names_to = "variable", 
               values_to = "value")

# 标准化数据(按变量分类标准化)
faithful_std <- ddply(faithful_long, .(variable), transform, 
                      value_std = scale(value)[,1])

# 原始数据分组核密度图
p1 <- ggplot(faithful_long, aes(x = value, fill = variable, color = variable)) +
  geom_density(position = "identity", alpha = 0.5) +
  scale_fill_brewer(palette = "Set2") +
  scale_color_brewer(palette = "Set2") +
  labs(title = "分组核密度图(原始数据)", 
       x = "值", y = "密度") +
  mytheme

# 标准化数据分组核密度图
p2 <- ggplot(faithful_std, aes(x = value_std, fill = variable, color = variable)) +
  geom_density(position = "identity", alpha = 0.5) +
  scale_fill_brewer(palette = "Set2") +
  scale_color_brewer(palette = "Set2") +
  labs(title = "分组核密度图(标准化数据)", 
       x = "标准化值", y = "密度") +
  mytheme

# 合并图形
library(patchwork)
p1 + p2

4.3 分面核密度图

library(ggplot2)
library(tidyr)
library(dplyr)
library(plyr)

# 预设主题
mytheme <- theme_bw() +
  theme(plot.title = element_text(hjust = 0.5),
        panel.grid.major = element_line(color = "grey90"),
        panel.grid.minor = element_blank())

# 将数据转为长格式
faithful_long <- faithful %>%
  pivot_longer(cols = c(eruptions, waiting), 
               names_to = "variable", 
               values_to = "value")

# 标准化数据(按变量分类标准化)
faithful_std <- ddply(faithful_long, .(variable), transform, 
                      value_std = scale(value)[,1])

# 原始数据分面核密度图
p1 <- ggplot(faithful_long, aes(x = value)) +
  geom_density(fill = "steelblue", alpha = 0.5) +
  facet_wrap(~variable, scales = "free") +
  labs(title = "分面核密度图(原始数据)", 
       x = "值", y = "密度") +
  mytheme

# 标准化数据分面核密度图
p2 <- ggplot(faithful_std, aes(x = value_std)) +
  geom_density(fill = "salmon", alpha = 0.5) +
  facet_wrap(~variable, scales = "free") +
  labs(title = "分面核密度图(标准化数据)", 
       x = "标准化值", y = "密度") +
  mytheme

# 合并图形
library(patchwork)
p1 + p2

4.4 镜像核密度图

library(ggplot2)
library(tidyr)
library(dplyr)
library(plyr)

# 预设主题
mytheme <- theme_bw() +
  theme(plot.title = element_text(hjust = 0.5),
        panel.grid.major = element_line(color = "grey90"),
        panel.grid.minor = element_blank())

# 将数据转为长格式
faithful_long <- faithful %>%
  pivot_longer(cols = c(eruptions, waiting), 
               names_to = "variable", 
               values_to = "value")

# 标准化数据(按变量分类标准化)
faithful_std <- ddply(faithful_long, .(variable), transform, 
                      value_std = scale(value)[,1])

# 原始数据镜像核密度图
p1 <- ggplot() +
  # eruptions (正方向)
  geom_density(data = subset(faithful_long, variable == "eruptions"),
               aes(x = value, y = ..density..), 
               fill = "#66C2A5", alpha = 0.7) +
  # waiting (负方向)
  geom_density(data = subset(faithful_long, variable == "waiting"),
               aes(x = value, y = -..density..), 
               fill = "#FC8D62", alpha = 0.7) +
  # 添加标签
  annotate("text", x = c(2, 80), y = c(0.5, -0.02),
           label = c("eruptions", "waiting"), 
           color = c("#66C2A5", "#FC8D62"), size = 5) +
  labs(title = "镜像核密度图(原始数据)", 
       x = "值", y = "密度") +
  mytheme

# 标准化数据镜像核密度图
p2 <- ggplot() +
  # eruptions (正方向)
  geom_density(data = subset(faithful_std, variable == "eruptions"),
               aes(x = value_std, y = ..density..), 
               fill = "#66C2A5", alpha = 0.7) +
  # waiting (负方向)
  geom_density(data = subset(faithful_std, variable == "waiting"),
               aes(x = value_std, y = -..density..), 
               fill = "#FC8D62", alpha = 0.7) +
  # 添加标签
  annotate("text", x = c(1.5, 1.5), y = c(0.4, -0.4),
           label = c("eruptions", "waiting"), 
           color = c("#66C2A5", "#FC8D62"), size = 5) +
  labs(title = "镜像核密度图(标准化数据)", 
       x = "标准化值", y = "密度") +
  mytheme

# 合并图形
library(patchwork)
p1 + p2

4.5 图形观察和代码编写的心得体会

  • 叠加直方图:图(a)呈现原始数据下 “eruptions” 和 “waiting” 的分布,能看出两者分布差异显著,“eruptions” 集中在左侧,“waiting” 在右侧。图(b)是标准化后数据的叠加直方图,消除量纲影响,更便于对比分布形态,分布特征在标准化后有新呈现。

  • 核密度图:图中核密度图展示变量分布的平滑曲线。图(c)将 “eruptions” 和 “waiting” 以镜像方式呈现,直观展现两者分布范围和密度差异。图(d)是标准化后的镜像核密度图,进一步消除原始量纲影响,能清晰观察两者分布特征和相对关系,如分布的对称性、峰值位置等。

5 箱线图和小提琴图

5.1 绘图要求

  • 根据实际数据和标准化后的数据绘制eruptionswaiting两个变量的箱线图geom_boxplot和小提琴图geom_violin

  • 采用stat_summary(fun="mean",geom="point")在箱线图和均值图中要添加均值点。

  • 小提琴图中要加入点图和箱线图

  • 采用调色板前两种颜色,brewer.pal(6,"Set2")[1:2] ,作为箱体填充颜色。

"#66C2A5" "#FC8D62" "#8DA0CB" "#E78AC3" "#A6D854" "#FFD92F"

5.2 箱线图代码

mytheme<-theme(plot.title=element_text(size="11"), # 设置主标题字体大小
   axis.title=element_text(size=10),               # 设置坐标轴标签字体大小
   axis.text=element_text(size=9),                # 设置坐标轴刻度字体大小
   legend.text=element_text(size="8"))            # 设置图例字体大小

df<-data |>  
  gather(everything(),key=指标,value=指标值) |> 
  mutate(指标=fct_inorder(指标))

palette<-RColorBrewer::brewer.pal(6,"Set2")[1:2]          # 设置离散型调色板
p1<-ggplot(df,aes(x=指标,y=指标值))+
  geom_boxplot(fill=palette)+      # 绘制箱线图并设置填充颜色
  stat_summary(fun="mean",geom="point",shape=21,size=2.5,fill="white")+
  ggtitle("(a) 原始数据箱线图")

df<-data |>         #标准化后
  gather(everything(),key=指标,value=指标值) |> 
  mutate(指标=fct_inorder(指标)) |> 
  ddply("指标",transform,标准化值=scale(指标值))
 
p2<-ggplot(df,aes(x=指标,y=标准化值))+
  geom_boxplot(fill=palette)+      # 绘制箱线图并设置填充颜色
  stat_summary(fun="mean",geom="point",shape=21,size=2.5,fill="white")+
  ggtitle("(b) 标准化数据箱线图")

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

5.3 小提琴图代码

  • 通过d3r::d3_nest将数据框转化为层次数据“d3.js”作为绘图输入
# 数据处理
df<-data |>                 
  gather(everything(),key=指标,value=指标值) |>  # 融合数据
  mutate(指标=fct_inorder(指标)) |> 
  ddply("指标",transform,标准化值=scale(指标值))    # 计算标准化值

# 设置图形主题
mytheme<-theme(plot.title=element_text(size="11"), # 设置主标题字体大小
   axis.title=element_text(size=10),               # 设置坐标轴标签字体大小
   axis.text=element_text(size=9),                # 设置坐标轴刻度字体大小
   legend.text=element_text(size="8"))            # 设置图例字体大小

# 图(a)原始数据小提琴图
p1<-ggplot(df,aes(x=指标,y=指标值,fill=指标))+
     geom_violin(scale="width",trim=FALSE)+
     geom_point(color="black",size=0.8)+  # 添加点
     geom_boxplot(outlier.size=0.7,outlier.color="white",size=0.3,
               width=0.2,fill="white")+  # 添加并设置箱线图和离群点参数
     scale_fill_brewer(palette="Set2")+
     stat_summary(fun=mean,geom="point",shape=21,size=2)+# 添加均值点
     guides(fill="none")+
     ggtitle("(a) 原始数据小提琴图")

# 图(b)数据标准化后的小提琴图
p2<-ggplot(df,aes(x=指标,y=标准化值,fill=指标))+
     geom_violin(scale="width")+
     #geom_point(color="black",size=1)+
     geom_boxplot(,outlier.size=0.7,outlier.color="black",size=0.3,
          width=0.2,fill="white")+
     scale_fill_brewer(palette="Set2")+
     guides(fill="none")+
     ggtitle("(b) 标准化小提琴图")

gridExtra::grid.arrange(p1,p2,ncol=2)        # 组合图形p1和p2

5.4 图形观察和代码编写的心得体会

  • 箱线图:直接展示数据分布的五数概括(最小值、Q1、中位数、Q3、最大值)和离群点,标准化前后对比明显(图b消除量纲差异),但无法展示分布密度。小提琴图:结合核密度估计(展示数据分布形状)和箱线图(展示统计量),原始数据图(a)能同时看到双峰分布特征和统计量,标准化图(b)更侧重比较分布形态相似性

  • 两种图形均采用gather+mutate+ddply的标准化数据处理流程,保证代码可复用性。小提琴图通过geom_violin+geom_boxplot+stat_summary多层叠加,既展示分布形状又强调关键统计量(如均值/四分位数)。采用调色板前两种颜色,brewer.pal(6,"Set2")[1:2] ,作为箱体填充颜色。

6 威尔金森点图、蜂群图和云雨图

6.1 绘图要求

  • 绘制eruptionswaiting 两个变量的威尔金森点图、蜂群图和云雨图。

  • 三种图形均采用标准化数据作图

  • 威尔金森点图采用geom_dotplot(binaxis="y",bins=30,dotsize = 0.3) ,要求作出居中堆叠和向上堆叠两种情况的图。

  • 蜂群图采用geom_beeswarm(cex=0.8,shape=21,size=0.8),要求作出不带箱线图和带有箱线图两种情况的图。

  • 云雨图采用geom_violindot(dots_size=0.7,binwidth=0.07) ,要求作出横向和纵向图两种情况的图。

6.2 威尔金森点图代码

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

mytheme<-theme_bw()+theme(legend.position="none")

df <- data|>
  gather(eruptions,waiting,key=指标,value=指标值)%>%# 融合数据
  ddply("指标",transform,标准化值=scale(指标值))

p<-ggplot(df,aes(x=指标,y=标准化值,fill=指标))
p1<-p+geom_dotplot(binaxis="y",bins=30,dotsize = 0.3,stackdir="center")+ # 绘制点图
  mytheme+ggtitle("(a) 居中堆叠")
p2<-p+geom_dotplot(binaxis="y",bins=30,dotsize = 0.3)+ # 绘制点图
  mytheme+ggtitle("(b) 向上堆叠")
gridExtra::grid.arrange(p1,p2,ncol=2)  

6.3 蜂群图代码

library(ggbeeswarm)
df <- data|>
  gather(eruptions,waiting,key=指标,value=指标值)%>%# 融合数据
  ddply("指标",transform,标准化值=scale(指标值))

# 图(a)5项指标的蜂群图
mytheme<-theme_bw()+theme(legend.position="none")
p<-ggplot(df,aes(x=指标,y=标准化值))
p1<-p+geom_beeswarm(cex=0.8,shape=21,fill="black",size=0.7,aes(color=指标))+# 设置蜂群的宽度、点的形状、大小和填充颜色
mytheme+ggtitle("(c) 蜂群图")

# 图(b)箱线图+蜂群图
p2<-p+geom_boxplot(size=0.5,outlier.size=0.8,aes(color=指标))+
geom_beeswarm(shape=21,cex=0.8,size=0.8,aes(color=指标))+
mytheme+ggtitle("(d) 箱线图+蜂群图")

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

6.4 云雨图代码

library(see)  # 提供主题函数theme_modern
df <- data|>
  gather(eruptions,waiting,key=指标,value=指标值)%>%# 融合数据
  ddply("指标",transform,标准化值=scale(指标值))
mytheme<-theme_modern()+
         theme(legend.position="none",
               plot.title=element_text(size=14,hjust=0.5))   # 调整标题位置
p1<-ggplot(df,aes(x=指标,y=标准化值,fill=指标))+
  geom_violindot(dots_size=0.7,binwidth=0.07)+ # 绘制云雨图并设置点的大小和箱宽
  mytheme+ggtitle("(e) 垂直排列(默认)")

p2<-ggplot(df,aes(x=指标,y=标准化值,fill=指标))+
  geom_violindot(dots_size=0.7,binwidth=0.07)+
  coord_flip()+mytheme+ggtitle("(f) 水平排列")

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

6.5 图形观察和代码编写的心得体会

  • 图(a)居中堆叠与图(b)向上堆叠,通过点的分布展示数据离散情况,可直观对比两指标标准化值的分布范围与集中趋势。

  • 蜂群图:图(c)蜂群图将数据点有序排列,更清晰展现数据分布形态;图(d)结合箱线图与蜂群图,既呈现数据分布特征(如中位数、四分位数等),又展示具体数据点分布。

  • 小提琴图变体:图(e)垂直排列(默认)和图(f)水平排列,在小提琴图基础上加入数据点,不仅展示分布密度,还能看到具体数据点位置,帮助理解数据分布的同时,体现数据离散程度。垂直排列便于上下对比,水平排列则利于横向观察分布区间。