news 2026/9/14 17:09:23

使用 R 与 ggplot2 可视化数据分布:直方图与密度图实战(Data Science for Beginners 第 10 课)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用 R 与 ggplot2 可视化数据分布:直方图与密度图实战(Data Science for Beginners 第 10 课)

使用 R 与 ggplot2 可视化数据分布:直方图与密度图实战(Data Science for Beginners 第 10 课)

【免费下载链接】Data-Science-For-Beginners10 Weeks, 20 Lessons, Data Science for All!项目地址: https://gitcode.com/GitHub_Trending/da/Data-Science-For-Beginners

数据科学的日常工作中,除了看"多少"(数量),更常需要回答"如何分布"(distribution)——数据沿坐标轴如何组织、集中在哪个区间、是否存在偏态。本课以明尼苏达州鸟类数据集(data/birds.csv)为例,系统讲解如何用 R 的ggplot2包构建直方图(histogram)、2D 直方图与密度图(density plot)来洞察数据分布,并处理文本型变量的可视化难题。读完本文,你将掌握binsadjustalphafill等核心参数的实际用法,并能独立完成"任意数据集 → 分布探索"的完整流程。

前置准备:加载数据并清洗异常值

本课延续上一课《使用 R 与 ggplot2 可视化数量》的工作流。在上一课中我们发现,Bald Eagle 与 Prairie Falcon 的MaxWingspan疑似多了一个 0,属于录入错误,因此先加载数据并按MaxWingspan < 500过滤掉这些异常值。

在 R 控制台中执行:

library(ggplot2) birds <- read.csv("data/birds.csv", fileEncoding = "UTF-8-BOM") birds_filtered <- subset(birds, MaxWingspan < 500) head(birds_filtered)

说明:fileEncoding = "UTF-8-BOM"用于正确处理带 BOM 头的 UTF-8 文件,避免第一列列名出现乱码。从仓库数据文件 data/birds.csv 的原始内容可以看到,文件第一行确实以 BOM 字符开头,13 列分别为Name, ScientificName, Category, Order, Family, Genus, ConservationStatus, MinLength, MaxLength, MinBodyMass, MaxBodyMass, MinWingspan, MaxWingspan

过滤后的数据前几行如下(法语文档与英文原版中均给出同一份示例,反映的是雁鸭类水鸟的测量数据):

名称学名类别保护状态最小体长最大体长最小体重最大体重最小翼展最大翼展
黑腹树鸭Dendrocygna autumnalis鸭/鹅/水禽AnseriformesAnatidaeDendrocygnaLC475665210207694
茶色树鸭Dendrocygna bicolor鸭/鹅/水禽AnseriformesAnatidaeDendrocygnaLC455371210508593
雪雁Anser caerulescens鸭/鹅/水禽AnseriformesAnatidaeAnserLC647920504050135165
罗斯雁Anser rossii鸭/鹅/水禽AnseriformesAnatidaeAnserLC57.36410661567113116
白额雁Anser albifrons鸭/鹅/水禽AnseriformesAnatidaeAnserLC648119303310130165

先用散点图初探分布:为什么它不够用

分布探索的直觉起点是散点图——把每个观测值按类别摊开来看。按鸟类的"目"(Order)绘制MaxLength的散点,并用coord_flip()把坐标轴翻转成横向,便于阅读较长的类别名:

ggplot(data = birds_filtered, aes(x = Order, y = MaxLength, group = 1)) + geom_point() + ggtitle("Max Length per order") + coord_flip()

这张图给出了不同目的鸟体长的大致分布轮廓,但它并非展示"真实分布"的最优形式:点的堆叠程度难以量化,密集区间与稀疏区间无法用视觉精确比较。这正是直方图(Histogram)的用武之地——它把连续数值轴切成若干等宽区间(bins),用柱高表示落入每个区间的观测频数。

直方图入门:bins 参数如何改变解读

ggplot2通过geom_histogram()提供直方图能力。它的形态类似柱状图,但 x 轴是连续数值变量,柱子的"升起与落下"直接反映数据的集中与分散。构建直方图的前提是数值型数据

对过滤后的数据绘制MaxBodyMass(最大体重)的分布,先设定 10 个区间:

ggplot(data = birds_filtered, aes(x = MaxBodyMass)) + geom_histogram(bins = 10) + ylab('Frequency')

可以看到,数据集里 400 多种鸟中的大多数,其最大体重落在 2000(克)以下,分布呈现明显的右偏(长尾朝右)形态。

bins是直方图最关键的分辨率参数:值越大,柱子越细,分布细节越丰富;值越小,曲线越平滑,但可能掩盖多峰结构。把bins提高到 30:

ggplot(data = birds_filtered, aes(x = MaxBodyMass)) + geom_histogram(bins = 30) + ylab('Frequency')

粒度变细后,可以观察到更多局部的起伏。若希望得到一个左侧偏斜更小、形态更"规整"的分布图,可以进一步对数据范围做过滤——只保留体重在 1~60 之间的鸟,仍用 30 个区间:

birds_filtered_1 <- subset(birds_filtered, MaxBodyMass > 1 & MaxBodyMass < 60) ggplot(data = birds_filtered_1, aes(x = MaxBodyMass)) + geom_histogram(bins = 30) + ylab('Frequency')

✅ 动手练习:尝试更换不同的过滤区间与数据点(例如MinLengthMaxWingspan)。若想观察数据的完整分布,可去掉体重过滤,直接对birds_filtered绘制带标签的分布图,比较"全量"与"局部"两种视角的差异。

二维直方图:同时比较两个分布的关系

直方图还能提供更强的颜色与标注能力。当需要比较两个分布之间的关系时,可以使用geom_bin2d()构建二维直方图:x 轴与 y 轴各为一个数值变量,格子颜色越亮代表该区域的观测越密集。

MaxBodyMassMaxLength为例,ggplot2内置的viridis色板用更鲜艳的颜色凸显高密度收敛点:

ggplot(data = birds_filtered_1, aes(x = MaxBodyMass, y = MaxLength)) + geom_bin2d() + scale_fill_continuous(type = "viridis")

从图中可以看出,两者沿一条预期的对角线方向存在相关性,并在某个区间出现一个特别强的收敛点——体重中等偏小的鸟占据了样本的主体。二维直方图是快速判断"两变量是否共同集中"的有效工具。

文本数据的分布:以 IUCN 保护状态为例

直方图默认针对数值数据效果最佳。那么面对文本型(分类)数据时,如何考察分布?

鸟类数据集中还包含类别(Category)、属(Genus)、科(Family)以及保护状态(ConservationStatus)等文本信息。我们关心的问题是:不同保护状态下的鸟,其最小翼展分布如何?

首先需要理解保护状态缩写,它们来自IUCN 红色名录(IUCN Red List)的物种状态分类:

  • CR:极危(Critically Endangered)
  • EN:濒危(Endangered)
  • EX:灭绝(Extinct)
  • LC:无危(Least Concern)
  • NT:近危(Near Threatened)
  • VU:易危(Vulnerable)

由于ConservationStatus是文本值,直接作为直方图的 x 轴无法工作,需要做一步重编码变换:把各状态映射为有序的数值/字符标签(x1~x6),使它们能按逻辑顺序参与绘图:

birds_filtered_1$ConservationStatus[birds_filtered_1$ConservationStatus == 'EX'] <- 'x1' birds_filtered_1$ConservationStatus[birds_filtered_1$ConservationStatus == 'CR'] <- 'x2' birds_filtered_1$ConservationStatus[birds_filtered_1$ConservationStatus == 'EN'] <- 'x3' birds_filtered_1$ConservationStatus[birds_filtered_1$ConservationStatus == 'NT'] <- 'x4' birds_filtered_1$ConservationStatus[birds_filtered_1$ConservationStatus == 'VU'] <- 'x5' birds_filtered_1$ConservationStatus[birds_filtered_1$ConservationStatus == 'LC'] <- 'x6'

接下来,把MinWingspan作为 x 轴、ConservationStatus作为填充色,绘制叠加直方图。这里用到三个关键参数:

  • position = "identity":各状态的柱子不堆叠,而是直接叠加,便于比较形状差异;
  • alpha = 0.4:设置透明度,避免相互遮挡时完全看不清;
  • scale_fill_manual():手动指定填充颜色与图例标签。
ggplot(data = birds_filtered_1, aes(x = MinWingspan, fill = ConservationStatus)) + geom_histogram(position = "identity", alpha = 0.4, bins = 20) + scale_fill_manual( name = "Conservation Status", values = c("red", "green", "blue", "pink"), labels = c("Endangered", "Near Threatened", "Vulnerable", "Least Concern") )

结果显示:最小翼展与保护状态之间没有明显的相关性——不同状态类别的分布相互重叠,形态接近。这是一个典型的"负结果"探索,同样有价值:它说明仅凭翼展这一维度无法区分濒危与否。你可以用同样的方法测试数据集中的其他要素(如体长、体重、目),或者更换不同的过滤条件,看看能否发现某种关联。

密度图:让分布曲线流动起来

细心的读者会发现,此前所有直方图都是"阶梯状"的——柱子边缘生硬,无法形成平滑的拱形轮廓。若要展示更平滑的密度形态,应改用密度图(density plot)ggplot2中对应geom_density()

先对birds_filtered_1MinWingspan绘制密度曲线:

ggplot(data = birds_filtered_1, aes(x = MinWingspan)) + geom_density()

可以看到,这条曲线与之前的直方图形状相呼应,但变得平滑流畅。同理,之前那张"锯齿感"较强的MaxBodyMass直方图(30 bins 版本),也可以用密度图重新表达,得到非常光滑的形态:

ggplot(data = birds_filtered_1, aes(x = MaxBodyMass)) + geom_density()

adjust 参数:控制平滑程度

密度图默认的平滑程度未必适合所有数据。若希望曲线"平滑但不过度平滑",可调整adjust参数——它控制核密度估计的带宽缩放倍数,值越小,曲线对局部细节越敏感、越显粗糙:

ggplot(data = birds_filtered_1, aes(x = MaxBodyMass)) + geom_density(adjust = 1/5)

对比上一张图可以看出,adjust = 1/5保留了更多局部起伏,同时整体仍比直方图平滑。

✅ 动手练习:查阅geom_density()的其他参数(如bwkerneltrim)并逐一实验,理解它们对曲线形态的影响。

按分组填充:一次看遍所有目的密度

密度图组合能力极强——只需几行代码,就能把所有目的体重密度叠加展示。给Order加上fill并设置透明度alpha = 0.5,各目之间的分布差异一目了然:

ggplot(data = birds_filtered_1, aes(x = MaxBodyMass, fill = Order)) + geom_density(alpha = 0.5)

这种"分组密度叠加"是直方图难以媲美的:它既展示了每个组的分布形态,又通过半透明填充保留了组间重叠信息,非常适合横向比较。

深入一步:geom_density_2d 与自学方向

密度图家族还有一个进阶成员:geom_density_2d(),即"一维或多维的连续概率密度曲线"。它在二维平面上用等高线刻画两个变量联合分布的密度,可视为本文二维直方图(geom_bin2d)的平滑版本。建议阅读官方文档理解其工作机制,并尝试与geom_point()叠加使用。

🚀 挑战:直方图的行业应用调研

直方图是一种比基础散点图、柱状图、折线图更"进阶"的图形类型。请上网搜索直方图的优秀应用案例:它通常被用于哪些场景、能够证明什么问题、集中在哪些学科领域(如统计学、医学检验、质量控制、影像处理等)?结合你找到的案例,回到本数据集继续试验。

复习小结

本课围绕"分布可视化"完成了从入门到进阶的完整路线:

  1. 数据准备:读取 data/birds.csv,用subset(birds, MaxWingspan < 500)剔除异常值;
  2. 直方图geom_histogram()+bins控制粒度,过滤子集改善偏态;
  3. 二维直方图geom_bin2d()+viridis色板考察双变量收敛关系;
  4. 文本数据分布:IUCN 状态重编码 +fill/alpha/scale_fill_manual叠加直方图;
  5. 密度图geom_density()平滑分布,adjust控制平滑程度,按Order分组叠加。

每次可视化前都要问自己:数据是数值型还是文本型?我想回答的是"集中在哪里"还是"组间有何差异"?这决定了直方图、二维直方图还是密度图更合适。

课后作业:技能实战

将本课技术迁移到新数据集:从 Kaggle 等平台挑选一个你感兴趣的数据集,编写 R 脚本讲述其中故事,并确保至少使用 5 个直方图来发现数据事实。评分标准可参考关联作业文档 translations/fr/3-Data-Visualization/R/10-visualization-distributions/assignment.md:

优秀合格待改进
脚本含数据集来源等完整注释,且至少使用 5 个直方图发现数据事实脚本注释不完整或存在错误脚本无注释且包含错误

相关资源:本课配套 Python 版本见 3-Data-Visualization/10-visualization-distributions/README.md,上一课《可视化数量》见 3-Data-Visualization/R/09-visualization-quantities/README.md,英文原版分布课文档见 3-Data-Visualization/R/10-visualization-distributions/README.md。

【免费下载链接】Data-Science-For-Beginners10 Weeks, 20 Lessons, Data Science for All!项目地址: https://gitcode.com/GitHub_Trending/da/Data-Science-For-Beginners

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 17:04:31

Laravel与ThinkPHP全面对比:团队与个人开发者如何选型?

我一直觉得&#xff0c;PHP圈子里最容易引战的话题&#xff0c;不是某个编辑器好不好用&#xff0c;也不是该不该上PHP 8&#xff0c;而是Laravel和ThinkPHP到底哪个强。这个问题你扔到群里&#xff0c;能吵出几十层高楼&#xff0c;吵完了谁也没说服谁。原因很简单&#xff0c…

作者头像 李华
网站建设 2026/9/14 17:03:40

Bokeh 数学符号渲染完全指南:在图表与控件中使用 LaTeX 和 MathML

Bokeh 数学符号渲染完全指南&#xff1a;在图表与控件中使用 LaTeX 和 MathML 【免费下载链接】bokeh Interactive Data Visualization in the browser, from Python 项目地址: https://gitcode.com/GitHub_Trending/bo/bokeh Bokeh 原生支持在图表中渲染数学公式&#…

作者头像 李华
网站建设 2026/9/14 17:02:31

2026 GEO工具选型指南:从RAG原理到五款主流产品PoC验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/14 17:01:59

LaTeX数学动画像素跳动的根源与七步精准控制

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华