跳至主要内容

R 中的 ggplot2 直方图:完整教程与示例

学习在 R 中创建与自定义 ggplot2 直方图:从基础绘图到着色、分面与密度叠加。
· 7分钟 阅读

使用 AI 探索

直方图能让您一眼看出数据分布的形状。在本教程中,我将带您使用 ggplot2(R 中最常用的绘图库,也是 tidyverse 生态的核心组成部分)来创建和自定义直方图。ggplot2 遵循“图形语法”,通过分层叠加图形元素来构建复杂可视化。若想使用 base R 的方法,请参阅我们的base R 直方图教程。

要点速览

  • 在 ggplot() 调用中使用 geom_histogram() 绘制直方图

  • 在 geom_histogram() 中用 bins 控制箱数,或用 binwidth 控制箱宽

  • 使用 color(边框)和 fill(填充)参数自定义柱形颜色

  • 将 y = after_stat(density) 设定后,使用 geom_density() 叠加密度曲线

  • 在 aes() 中用 fill = 变量 按类别着色,或使用 facet_grid() 分面显示

什么是直方图?

直方图是一种展示连续(数值)变量频率分布的可视化。它能让我们看到数据中观测值在连续变量所覆盖范围内各区间的计数。

开始使用 ggplot2

要跟随本教程,您需要安装 R 以及以下包:ggplot2、readr 和 dplyr。下一节的代码会在尚未安装的情况下进行安装。

安装包

我们首先需要使用 library 函数导入 ggplot2 库。这将引入 ggplot2 中所有可用的内置函数。如果您尚未安装 ggplot2,需要运行 install.packages() 进行安装。对于可读取 CSV 文件的 readr 库和便于处理数据的 dplyr,我们也将执行相同操作。 

install.packages("ggplot2")
install.packages("readr")
install.packages("dplyr")
library(ggplot2)
library(readr)
library(dplyr)

加载数据集

本教程将使用这个房屋数据集,其中包含不同房源的详细信息,包括房屋面积、房间数量、价格和位置信息。 

我们可以使用 read_csv() 函数读取数据。可直接从 URL 读取,或将 CSV 文件下载到本地目录后再从本地读取。read_csv() 的第一个参数是数据位置,col_select 参数可让我们选择感兴趣的列。 

home_data <- read_csv(
    "https://raw.githubusercontent.com/rashida048/Datasets/master/home_data.csv",
    col_select = c(price, condition)
)

随后我们可以使用 head() 函数查看前几行数据:

head(home_data)

房屋数据集的前几行,展示 price 和 condition 两列

如何用 ggplot2 绘制直方图

现在我们来创建直方图。无论在 ggplot2 中绘制何种图形,我们总是从 ggplot() 函数开始,它会创建一个用于叠加图形元素的画布。它接收两个参数。

  • 第一个参数是数据框。这里我们使用 home_data。

  • 第二个参数是数据框列到图形美学属性的映射。该映射需要调用 aes() 函数。这里我们将 price 列映射到 x 轴。

到目前为止,代码如下:

ggplot(data = home_data, aes(x = price))

这段代码本身不会绘制出有用的内容。要使其成为直方图,我们需添加直方图几何图层 geom_histogram()。

ggplot(data = home_data, aes(x = price)) +
  geom_histogram()

房价的基础 ggplot2 直方图

使用 geom_vline() 为直方图添加描述性统计

我们可以使用 geom_vline() 函数为图表添加描述性统计信息。它会在图中添加一条垂直线。

首先,使用 dplyr 的 summarize() 计算一项描述性统计,这里以均价为例。

price_stats <- home_data |>
summarize(mean_price = mean(price))
price_stats
# A tibble: 1 × 1
  mean_price
      <dbl>
1    540088.

该函数接收 xintercept 参数,以及可选的 color 与 linewidth 参数分别自定义线条颜色和粗细。我们将像上一节一样用加号添加一条均值线。

ggplot(home_data, aes(x = price)) +
    geom_histogram() +
    geom_vline(aes(xintercept = mean_price), price_stats, color = "red", linewidth = 2)

请注意,在 geom_ 函数中,mapping 与 data 参数的顺序与 ggplot() 相比是对调的。

通过 geom_vline() 添加红色均价竖线的 ggplot2 直方图

绘制定概率密度而非计数

要在直方图上添加概率密度曲线,我们首先将 y 轴改为密度刻度。在 aes() 函数中,将 y 设为 after_stat(density)。 

随后使用 geom_density() 为图表添加密度图层。这里我们将 color 设为绿色,linewidth 设为 2。

ggplot(home_data, aes(x = price, y = after_stat(density))) +
    geom_histogram() +
    geom_vline(aes(xintercept = mean_price), price_stats, color = "red", linewidth = 2) +
    geom_density(color = "green", linewidth = 2)

image4.png

请注意 y 轴的数值已经改变。

再观察一下,每一层都遵循相同的模式:一个 + 号、一个函数调用,以及可选参数。您可以自由添加 geom_ 函数、统计和主题,而无需为每种组合重新学习语法。

使用 bins 更新分箱

我们可以用 bin 属性更新 ggplot2 直方图的分箱。将 bin 属性设置为希望在图上显示的箱数,可帮助我们在直方图中查看更多或更少的粒度。 

ggplot(data = home_data, aes(x = price)) +
  geom_histogram(bins = 100)

image12.png

我们也可以使用 geom_histogram() 的 binwidth 属性手动设置箱宽。

ggplot(data = home_data, aes(x = price)) +
  geom_histogram(binwidth = 50000)

image5.png

最后,您可以使用 center 或 boundary 属性对齐箱边界。如果希望箱的边界落在特定的倍数上,可以使用这些属性(一次只能使用一个)。例如要确保箱边界落在整数上,将该属性设为 1。   

ggplot(data = home_data, aes(x = price)) +
  geom_histogram(boundary = 1)

使用 boundary 参数对齐箱边界的 ggplot2 直方图

自定义直方图颜色

本节我们将更改直方图的颜色。可使用 color 属性自定义每个柱形的边框颜色,使用 geom_histogram() 的 fill 属性更改柱形填充颜色。我们将以蓝色填充柱形,并将边框颜色改为白色。 

ggplot(data = home_data, aes(x = price)) +
  geom_histogram(color = "white", fill = "blue")

白色边框与蓝色填充的 ggplot2 直方图

按分组自定义 ggplot2 直方图颜色

您可以自定义直方图柱形的颜色。 

在 aes() 内更改 fill 美学映射,可根据数据集中某个变量的取值改变柱形的填充颜色。该变量应为分类变量(因子)而非整数,因此我们可以用 factor() 函数进行转换。本例中,我们查看 condition 变量,该值范围为 1(状况差)到 5(状况佳)。 

home_data <- home_data |>
    mutate(condition = factor(condition))

ggplot(data = home_data, aes(x = price, fill = condition)) +
    geom_histogram()

按房屋状况类别着色柱形的 ggplot2 直方图

使用 abs() 添加标签和标题

接下来,我们使用 labs() 函数为图表添加标题和标签。将 x、y 和 title 属性设置为所需文本。 

ggplot(data = home_data, aes(x = price)) +
  geom_histogram() +
  labs(x ='Price (USD)', y='Number of Listings', title = 'Housing Price Distributions')

自定义 x 轴、y 轴与标题标签的 ggplot2 直方图

使用 xlim() 设置 x 轴范围

我们可以使用 xlim()  函数设置图表的 x 轴范围,以便聚焦于感兴趣的数据。例如,有时聚焦分布的中心部分会比我们当前看到的长尾更有帮助。 

也可以更改 y 轴范围(使用 ylim()),但对直方图来说,这通常不太有用,因为自动计算的取值几乎总是理想的。

我们将把价格范围缩放到 0 至 200 万美元。

ggplot(home_data, aes(x = price)) +
    geom_histogram(bins = 100) +
    xlim(0, 2000000)

使用 xlim() 将 ggplot2 直方图缩放到 0 至 200 万美元价格区间

更改图例位置

如果我们希望移动图例位置,例如在用不同颜色展示 condition 时,可以使用 theme() 函数与 legend.position 属性。legend.position 的取值可为 “bottom”、“top”、“left” 或 “right”。您也可以通过传入 c(x, y) 坐标来指定图例位置。

ggplot(home_data, aes(x = price, fill = condition)) +
    geom_histogram() +
    theme(legend.position = "bottom")

在 ggplot2 中使用分面

最后,我们可以通过分面在不同的小图中展示各分组数据。这会针对每个类别拆分出若干子图。可使用 facet_grid() 实现。下面我们按不同的 condition 值可视化价格分布。 

ggplot(home_data, aes(x = price)) +
  geom_histogram() +  facet_grid(vars(condition))

有关分面的更多内容,请参阅R 中的 ggplot 分面教程。

image2.png

总结

在 ggplot2 中创建直方图的流程是:用 ggplot() 搭建基础,传入数据框与 aes() 映射,然后添加 geom_histogram()。在此基础上,叠加自定义层:用 labs() 设置坐标轴标题,xlim() 缩放 x 轴范围,theme() 重定位图例或调整视觉样式。

ggplot2 在 R 数据可视化技能路径中有深入讲解,从使用 ggplot2 入门数据可视化开始。您还可以在R 的 Tidyverse 基础技能路径中学习将 ggplot2 与其他 tidyverse 工具结合使用。

若想了解直方图之外的更多 ggplot2 图形类型,请参阅我们的ggplot2 图形教程,并下载一份ggplot2 备忘单以便随时查阅。

作者

Kevin Babitz

数据科学作者|Wayfair 高级技术营销分析师|宾夕法尼亚大学数据科学硕士(MSE)

主题