第四章 数据分布可视化

Author

221527108毕慧娈

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(e1071)        # 用于计算偏度系数和峰度系数

df <- data
# 作初始直方图,纵轴默认为频数
h1<-ggplot(data=df,aes(x=eruptions))+mytheme+    # 绘制直方图
  geom_histogram(aes(y=..density..),fill="lightgreen",color="gray50")+
  geom_rug(size=0.2,color="blue3")+ # 添加地毯图,须线的宽度为0.2
  geom_density(color="blue2",size=0.7)+ #添加核密度线
  annotate("text",x=2.5,y=0.7,label=paste0("偏度系数 =",round(skewness(df$eruptions),4)),size=3)+  # 添加注释文本
  geom_vline(xintercept=mean(df$eruptions),linetype="twodash",size=0.6,color="red")+ #添加理论正态曲线和均值线"
  annotate("text",x=mean(df$eruptions),y=0.7,label=paste0("均值线 =",round(skewness(df$eruptions),4)),size=3)
  
h1

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

  • 偏度系数(Skewness)

    • 结果显示 偏度系数 > 0(右偏分布),说明数据右侧有长尾

    • 从直方图可验证:右侧的核密度曲线拖尾比左侧更长

  • 峰度系数(Kurtosis)

    • 如果添加峰度计算,>3 表示比正态分布更陡峭(尖峰),<3 表示更平缓

    • 结合图形可判断数据是否存在”重尾”

  • 均值线位置

    • 红线标记的均值在右偏分布中会偏向右侧(因为少数大值拉高了均值)

    • 可与中位数对比(若添加 geom_vline(xintercept=median(...)))进一步验证偏态

      分布形态决定分析方法

      • 右偏数据可能需要对数变换后再进行参数检验

      • 若做回归分析,需检查异方差性

    • 可视化组合的威力

      • 直方图(分布轮廓) + 核密度线(平滑趋势) + 地毯图(实际数据点) + 统计量标注 = 四重信息整合

      • 你的代码已完美体现这一理念

    • 代码复用技巧

      • 将常用图形参数(如mytheme)保存为对象是优秀实践

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

3.1 绘图要求

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

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

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

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

3.2 叠加直方图代码

df <- data|> 
  gather(eruptions,waiting,key=指标,value=指标值) %>%  # 融合数据
  ddply("指标",transform,标准化值=scale(指标值))
p1<-ggplot(df)+aes(x=指标值,y=..density..,fill=指标)+
  geom_histogram(position="identity",color="gray60",alpha=0.5)+
  scale_fill_brewer(palette = "Set3")
  theme(legend.position=c(0.8,0.8),# 设置图例位置
       legend.background=element_rect(fill="grey90",color="grey"))+
                                                # 设置图例背景色和边框颜色
  ggtitle("原始数据叠加直方图")
List of 4
 $ legend.background     :List of 5
  ..$ fill         : chr "grey90"
  ..$ colour       : chr "grey"
  ..$ linewidth    : NULL
  ..$ linetype     : NULL
  ..$ inherit.blank: logi FALSE
  ..- attr(*, "class")= chr [1:2] "element_rect" "element"
 $ legend.position       : chr "inside"
 $ legend.position.inside: num [1:2] 0.8 0.8
 $ title                 : chr "原始数据叠加直方图"
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi FALSE
 - attr(*, "validate")= logi TRUE
p2<-ggplot(df)+aes(x=标准化值,y=..density..,fill=指标)+
  geom_histogram(position="identity",color="gray60",alpha=0.5)+
  scale_fill_brewer(palette = "Set3")
  theme(legend.position=c(0.8,0.8),# 设置图例位置
       legend.background=element_rect(fill="grey90",color="grey"))+
                                                # 设置图例背景色和边框颜色
    ggtitle("标准化数据叠加直方图")
List of 4
 $ legend.background     :List of 5
  ..$ fill         : chr "grey90"
  ..$ colour       : chr "grey"
  ..$ linewidth    : NULL
  ..$ linetype     : NULL
  ..$ inherit.blank: logi FALSE
  ..- attr(*, "class")= chr [1:2] "element_rect" "element"
 $ legend.position       : chr "inside"
 $ legend.position.inside: num [1:2] 0.8 0.8
 $ title                 : chr "标准化数据叠加直方图"
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi FALSE
 - attr(*, "validate")= logi TRUE
 gridExtra::grid.arrange(p1,p2,ncol=2) 

3.3 镜像直方图代码

df<-data |> 
 mutate(
   std.eruptions=scale(eruptions),
   std.waiting=scale(waiting)
 )
p2<-ggplot(df)+aes(x=x)+
   geom_histogram(aes(x=eruptions,y=..density..),color="grey50",fill="red",alpha=0.3,bins = 30)+ # 绘制直方图(上图)
   geom_label(aes(x=20,y=0.1),label="eruptions",color="red")+  # 添加标签
   geom_histogram(aes(x=waiting,y=-..density..),fill="blue",alpha=0.3)+ # 绘制PM2.5的直方图(下图)
   geom_label(aes(x=60,y=-0.075),label="PM2.5",color="blue")+  # 添加标签
   xlab("指标值")+ggtitle("(b) 原始数据镜像直方图")
p2

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

  • 3.4.0.1 标准化直方图(p1)

    • 观察重点:比较标准化前后两个变量的分布形态差异

      • 若标准化后曲线重合度高 → 原始分布形状相似,仅量纲不同

      • 右图中 waiting 的峰度明显更高(更尖的分布)

    3.4.0.2 2. 镜像直方图(p2)

    • 通过负坐标轴实现 空间复用,适合对比量纲差异大的变量

    • 红色(eruptions)呈双峰分布,蓝色(waiting)呈右偏分布 → 暗示数据可能存在两个亚群

      视觉认知优化

      • 对比图形应保持一致的色彩编码(如始终用红色表示eruptions)

      • 在镜像图中添加 y=0基准线geom_hline)能显著提升可读性

    • 代码健壮性

      • 管道操作符(|>)后换行时,必须以 + 开始新行(ggplot2语法要求)

      • 使用 bins 参数替代默认分箱,保证多图一致性

4 核密度图

4.1 绘图要求

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

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

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

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

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

4.2 分组核密度图

df<-data |> 
 mutate(
   std.eruptions=scale(eruptions),
   std.waiting=scale(waiting)
 )
p2<-ggplot(df)+aes(x=x)+
   geom_density(aes(x=eruptions,y=..density..),color="grey50",fill="red",alpha=0.3)+ # 绘制直方图(上图)
   geom_label(aes(x=20,y=0.1),label="eruptions",color="red")+  # 添加标签
   geom_density(aes(x=waiting,y=-..density..),fill="blue",alpha=0.3)+ # 绘制PM2.5的直方图(下图)
   geom_label(aes(x=60,y=-0.075),label="PM2.5",color="blue")+  # 添加标签
   xlab("指标值")+ggtitle("(b) 原始数据核密度图")
p2

4.3 分面核密度图

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


p3<-ggplot(df)+aes(x=标准化值,y=..density..,fill=指标)+
  geom_density(position="identity",color="gray60",alpha=0.5)+
  scale_fill_brewer(palette = "Set3")+
  facet_wrap(~指标,scale="free")+
  theme(legend.position = c(0.8,0.8),
        legend.background = element_rect(fill = "gray90",color = "grey"))
p3

4.4 镜像核密度图

ggplot(df) +
  aes(x = 标准化值, fill = 指标) +
  geom_density(aes(y = after_stat(density)), color = "gray60", alpha = 0.5) +
  geom_density(aes(y = -after_stat(density)), color = "gray60", alpha = 0.5) +
  scale_fill_brewer(palette = "Set3") +
  geom_hline(yintercept = 0, color = "gray50") +
  coord_flip() +  # 将x和y轴翻转以实现镜像效果
  theme(
    legend.position = c(0.8, 0.8),
    legend.background = element_rect(fill = "gray90", color = "grey")
  )

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

    • 视觉特征:通过 y=-..density.. 实现上下镜像,红色(eruptions)与蓝色(waiting)形成对称对比

    • 分布洞察

      • eruptions 呈现明显的双峰分布,暗示数据可能存在两种不同的喷发模式

      • waiting右偏分布,多数等待时间集中在60-80分钟区间

    • 改进点:建议添加 geom_hline(yintercept=0) 强化镜像分界效果

    4.5.0.1 2. 分面标准化密度图

    • 设计亮点:使用 facet_wrap(~指标) 实现分离式对比,避免重叠干扰

    • 统计意义:标准化后可直接比较分布形态差异(不受原始量纲影响)

    • 优化建议scale="free" 可能导致误解,相同量纲时建议用 scale="free_y"

    4.5.0.2 3. 创新镜像分面图

    • 创新性:结合 coord_flip() + 双向 after_stat(density) 创造垂直镜像效果

    • 独特价值:适合对比具有正负关联的变量(如收益与风险)

    • 注意点:坐标翻转后需重新调整标签位置

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 箱线图代码

library(tidyverse)
library(RColorBrewer)

# 自定义主题
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)
)

# 数据处理(使用现代tidyverse语法)
df <- data %>%
  pivot_longer(cols = c(eruptions, waiting), 
               names_to = "指标", 
               values_to = "指标值") %>%
  group_by(指标) %>%
  mutate(标准化值 = scale(指标值)) %>%
  ungroup()

# 取Set2调色板的前2种颜色(对应两个指标)
palette <- RColorBrewer::brewer.pal(6, "Set2")[1:2]

# 正确绘制箱线图
ggplot(df, aes(x = 指标, y = 指标值, fill = 指标)) +  # fill映射到分组变量
  geom_boxplot() +  # 不需要单独指定fill,通过aes映射
  stat_summary(
    fun = "mean", 
    geom = "point", 
    shape = 21, 
    size = 2.5, 
    fill = "white"
  ) +
  scale_fill_manual(values = palette) +  # 这里正确指定分组颜色
  mytheme

5.3 小提琴图代码

  • 通过d3r::d3_nest将数据框转化为层次数据“d3.js”作为绘图输入
library(tidyverse)
library(RColorBrewer)
library(d3r)  # 用于转换为d3.js层次数据
library(gridExtra)

# 数据处理管道
df <- data %>%
  pivot_longer(cols = c(eruptions, waiting), 
               names_to = "指标", 
               values_to = "指标值") %>%
  group_by(指标) %>%
  mutate(标准化值 = scale(指标值)) %>%
  ungroup()

# 转换为d3.js嵌套结构(备用)
d3_hierarchy <- d3r::d3_nest(df, value_cols = c("指标值", "标准化值"))

# 图形主题设置
mytheme <- theme(
  plot.title = element_text(size = 11, hjust = 0.5),
  axis.title = element_text(size = 10),
  axis.text = element_text(size = 9),
  legend.position = "none",
  panel.background = element_rect(fill = "white"),
  panel.grid.major.y = element_line(color = "grey90")
)

# 调色板设置(仅取前两种颜色)
violin_palette <- brewer.pal(6, "Set2")[1:2]

# 图(a) 原始数据小提琴图
p1 <- ggplot(df, aes(x = 指标, y = 指标值, fill = 指标)) +
  geom_violin(
    scale = "width", 
    trim = FALSE,
    alpha = 0.7,
    width = 0.8
  ) +
  geom_jitter(
    width = 0.15, 
    size = 1, 
    alpha = 0.4,
    color = "grey30"
  ) +
  geom_boxplot(
    width = 0.15,
    alpha = 0.9,
    outlier.shape = NA,
    fill = "white",
    color = "black"
  ) +
  stat_summary(
    fun = mean,
    geom = "point",
    shape = 23,
    size = 3,
    fill = "white",
    color = "black"
  ) +
  scale_fill_manual(values = violin_palette) +
  labs(title = "(a) 原始数据分布") +
  mytheme

# 图(b) 标准化数据小提琴图
p2 <- ggplot(df, aes(x = 指标, y = 标准化值, fill = 指标)) +
  geom_violin(
    scale = "width",
    alpha = 0.7,
    width = 0.8
  ) +
  geom_jitter(
    width = 0.15,
    size = 1,
    alpha = 0.4,
    color = "grey30"
  ) +
  geom_boxplot(
    width = 0.15,
    alpha = 0.9,
    outlier.shape = NA,
    fill = "white",
    color = "black"
  ) +
  stat_summary(
    fun = mean,
    geom = "point",
    shape = 23,
    size = 3,
    fill = "white",
    color = "black"
  ) +
  geom_hline(
    yintercept = 0,
    linetype = "dashed",
    color = "grey50"
  ) +
  scale_fill_manual(values = violin_palette) +
  labs(title = "(b) 标准化分布") +
  mytheme

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

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

  • 5.4.0.1 箱线图分析

    • 分布特征:通过箱线图可清晰观察到:

      • eruptions呈现双峰分布(箱体较宽,上下须长度不对称)

      • waiting呈现右偏分布(中位数靠近箱体底部,上须明显更长)

    • 异常值检测:箱线图自动标出的异常点(图中圆点)显示:

      • eruptions在短持续时间区域有较多异常值

      • waiting在长时间等待区域有少量异常值

    5.4.0.2 2. 标准化数据对比

    • 量纲统一:标准化后(均值0,标准差1):

      • eruptions的均值线明显低于0(原始量纲均值较小)

      • waiting的分布更接近标准正态(均值线接近0位置)

    • 形态保留:标准化不改变分布形状,仍保持原始数据的偏态特征

    5.4.0.3 3. 小提琴图增强分析

    • 概率密度展示:相比箱线图,小提琴图的宽度变化揭示:

      • eruptions在2分钟和4.5分钟处存在双峰密度

      • waiting在75分钟处有单峰密集分布

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")
p<-ggplot(df,aes(x=指标,y=指标值,fill=指标))
p1<-p+geom_dotplot(binaxis="y",binwidth=3,stackdir="center")+ # 绘制点图
  mytheme+ggtitle("(a) 居中堆叠")
p1

6.3 蜂群图代码

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

6.4 云雨图代码

library(see)  # 提供主题函数theme_modern
mytheme<-theme_modern()+
         theme(legend.position="none",
               plot.title=element_text(size=14,hjust=0.5))   # 调整标题位置
p3<-ggplot(df,aes(x=指标,y=指标值,fill=指标))+
  geom_violindot(dots_size=55,binwidth=0.07)+ # 绘制云雨图并设置点的大小和箱宽
  mytheme+ggtitle("(a) 垂直排列(默认)")

p4<-ggplot(df,aes(x=指标,y=指标值,fill=指标))+
  geom_violindot(dots_size=60,binwidth=0.06)+
  coord_flip()+mytheme+ggtitle("(b) 水平排列")

gridExtra::grid.arrange(p3,p4,ncol=2)        

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

  • 视觉特征:居中堆叠的点呈现垂直分布

  • 优势:直观展示数据密度分布,每个点代表一个观测值

  • 局限:当数据量大时可能出现重叠(binwidth=3可能偏大)

6.5.0.1 2. 蜂群图(Beeswarm Plot)

  • 创新点:采用geom_beeswarm实现非重叠点分布

  • 分布揭示:点的水平散开清晰显示:

    • eruptions在1.5-2分钟和4-4.5分钟形成双峰聚集

    • waiting在70-80分钟形成单峰密集分布

6.5.0.2 3. 云雨图(Raincloud Plot)

  • 复合可视化:整合小提琴图+箱线图+点图

  • 垂直vs水平

    • 垂直布局(p3)适合传统坐标轴阅读习惯

    • 水平布局(p4)方便长标签显示和跨群体比较